<?php class WoofiltersViewWpf extends ViewWpf { private static $uniqueBlockId = 0; private static $filterOrderKey = 0; protected static $blockId = ''; protected static $filtersCss = ''; protected static $isLeerFilter = false; public $settings = array( 'settings' => array() ); public $proLink = ''; public $linkSetting = ''; public $filter = array( 'id' => 0 ); protected static $currentSettings = array(); protected static $currentFilterRecount = false; /** * Filters with Taxonomy base terms list * We collect it with paying attention on a current wp_query and filtering results * * @var null|array */ public static $filterExistsTerms = null; /** * Filters with Taxonomy base terms list * We collect it without paying attention on a curren wp_query and filtering results * * @var null|array */ public static $filterExistsTermsWithotFiltering = null; /** * Exist Filters with user list * We collect it with paying attention on a current wp_query and filtering results * * @var null|array */ public static $filterExistsUsers; /** * Exist Filters with prices * We collect it with paying attention on a current wp_query and filtering results * * @var null|array */ public static $filterExistsPrices; /** * Filter id * * @var int */ public $filterId; /** * Post type product taxonomies dependency with standard product_cat as a keys. * * @var array */ public $taxonomyOptionality = array( 'pwb-brand' => array( 'thumbnail_id' => 'pwb_brand_image', ), ); /** * Specifies filter blocks to add indexes to * * @var array */ public $needIndex = array(); public static $filterExistsTermsJS = ''; public static $leer; public function setCurrentSettings( $settings ) { if (!isset($settings['settings'])) { $settings['settings'] = array(); } self::$currentSettings = $settings; } public function getCurrentSettings( $id = 0 ) { if (!empty($id)) { $settings = FrameWpf::_()->getModule('woofilters')->getModel('settings')->getFilterBlockSettings($id); if (!isset($settings['settings'])) { $settings['settings'] = array(); } self::$currentSettings = $settings; } return self::$currentSettings; } public function getTabContent() { $addWC = ( FrameWpf::_()->isWCLicense() ? '-wc' : '' ); FrameWpf::_()->getModule('templates')->loadJqGrid(); FrameWpf::_()->addScript('admin.woofilters.list', $this->getModule()->getModPath() . 'js/admin.woofilters.list.js'); FrameWpf::_()->addScript('adminCreateTableWpf', $this->getModule()->getModPath() . 'js/create-filter.js', array(), false, true); FrameWpf::_()->getModule('templates')->loadFontAwesome(); FrameWpf::_()->addJSVar('admin.woofilters.list', 'wpfTblDataUrl', UriWpf::mod('woofilters', 'getListForTbl', array('reqType' => 'ajax'))); FrameWpf::_()->addJSVar('admin.woofilters.list', 'url', admin_url('admin-ajax.php')); FrameWpf::_()->getModule('templates')->loadBootstrap(); FrameWpf::_()->addStyle('admin.filters', $this->getModule()->getModPath() . 'css/admin.woofilters' . $addWC . '.css'); $this->assign('addNewLink', FrameWpf::_()->getModule('options')->getTabUrl('woofilters#wpfadd')); return parent::getContent('woofiltersAdmin'); } public function getEditTabContent( $idIn ) { $isWooCommercePluginActivated = $this->getModule()->isWooCommercePluginActivated(); if (!$isWooCommercePluginActivated) { return; } $idIn = isset($idIn) ? (int) $idIn : 0; $filter = $this->getModel('woofilters')->getById($idIn); $settings = unserialize($filter['setting_data']); $modPath = $this->getModule()->getModPath(); $addWC = ( FrameWpf::_()->isWCLicense() ? '-wc' : '' ); FrameWpf::_()->getModule('templates')->loadChosenSelects(); FrameWpf::_()->getModule('templates')->loadBootstrap(); FrameWpf::_()->addScript('notify-js', WPF_JS_PATH . 'notify.js', array(), false, true); FrameWpf::_()->addScript('chosen.order.jquery.min.js', $modPath . 'js/chosen.order.jquery.min.js'); FrameWpf::_()->addScript('admin.filters', $modPath . 'js/admin.woofilters.js'); FrameWpf::_()->addScript('admin.wp.colorpicker.alhpa.js', WPF_JS_PATH . 'admin.wp.colorpicker.alpha.js', array('wp-color-picker')); FrameWpf::_()->addJSVar('wp-color-picker', 'wpColorPickerL10n', array()); FrameWpf::_()->addScript('adminCreateTableWpf', $modPath . 'js/create-filter.js', array(), false, true); FrameWpf::_()->addJSVar('admin.filters', 'url', admin_url('admin-ajax.php')); FrameWpf::_()->addStyle('admin.filters', $modPath . 'css/admin.woofilters' . $addWC . '.css'); $this->addCommonAssets($modPath); $this->addPluginCustomStyles($modPath, true); FrameWpf::_()->addScript('jquery.slider.js.jshashtable', $modPath . 'js/jquery_slider/jshashtable-2.1_src.js'); FrameWpf::_()->addScript('jquery.slider.js.numberformatter', $modPath . 'js/jquery_slider/jquery.numberformatter-1.2.3.js'); FrameWpf::_()->addScript('jquery.slider.js.dependClass', $modPath . 'js/jquery_slider/jquery.dependClass-0.1.js'); FrameWpf::_()->addScript('jquery.slider.js.draggable', $modPath . 'js/jquery_slider/draggable-0.1.js'); FrameWpf::_()->addScript('jquery.slider.js', $modPath . 'js/jquery_slider/jquery.slider.js'); FrameWpf::_()->addStyle('jquery.slider.css', $modPath . 'css/jquery.slider.min.css'); FrameWpf::_()->addStyle('loaders', $modPath . 'css/loaders.css'); DispatcherWpf::doAction('addScriptsContent', true, $settings); $link = FrameWpf::_()->getModule('options')->getTabUrl( $this->getCode() ); $linkSetting = FrameWpf::_()->getModule('options')->getTabUrl( 'settings' ); $proLink = FrameWpf::_()->getModule('promo')->getWooBeWooPluginLink(); $this->assign('proLink', $proLink); $this->assign('link', $link); $this->assign('linkSetting', $linkSetting); $this->assign('settings', $settings); $this->assign('filter', $filter); $this->assign('is_pro', FrameWpf::_()->isPro()); return parent::getContent('woofiltersEditAdmin'); } public function renderHtml( $params ) { $isWooCommercePluginActivated = $this->getModule()->isWooCommercePluginActivated(); if (!$isWooCommercePluginActivated) { return; } $id = isset($params['id']) ? (int) $params['id'] : 0; if (!$id) { return false; } FrameWpf::_()->getModule('meta')->calcNeededMetaValues(true); $this->assign('filterId', $id); $this->filter['id'] = $id; // preview case if ( isset( $params['settings'] ) ) { $params['settings']['filters']['order'] = stripcslashes( $params['settings']['filters']['order'] ); if ( ! empty( $params['settings']['css_editor'] ) ) { $params['settings']['css_editor'] = base64_encode( $params['settings']['css_editor'] ); } $settings = $params; // other } else { $settings = $this->getCurrentSettings( $id ); } if ( defined( 'WPF_FREE_REQUIRES' ) && version_compare( '1.4.9', WPF_FREE_REQUIRES, '==' ) ) { $preselects = DispatcherWpf::applyFilters( 'addDefaultFilterData', array(), $id, $settings ); } else { DispatcherWpf::doAction( 'addDefaultFilterData', $id, $settings ); } $recalculateFilters = $this->getFilterSetting( $settings['settings'], 'recalculate_filters', false ); if ( '1' === ReqWpf::getVar( 'wpf_skip' ) && ! $recalculateFilters ) { $fid = ReqWpf::getVar( 'wpf_fid' ); if ($fid) { $this->assign('html', '<div class="wpfExistsTermsJS" data-fid="' . esc_attr($fid) . '"></div>'); return parent::getContent('woofiltersHtml'); } return false; } if (!$settings || empty($settings['settings'])) { return false; } $isWidget = $this->getFilterSetting($params, 'mode', '') == 'widget'; $module = $this->getModule(); $mode = $module->getRenderMode($id, $settings, $isWidget); if (empty($mode)) { return false; } $html = ''; $modPath = $module->getModPath(); $module->setCurrentFilter($id, $isWidget); $this->addRenderHtmlAssets($modPath, $settings); $this->addPluginCustomStyles($modPath, $this->isCustomStyle($settings['settings'])); DispatcherWpf::doAction('addScriptsContent', false, $settings); $viewId = $id . '_' . mt_rand(0, 999999); switch ($mode) { case 1: //categoty page $catObj = get_queried_object(); $html = $this->generateFiltersHtml($settings, $viewId, $catObj->term_id); break; case 2: //shop page $html = $this->generateFiltersHtml($settings, $viewId); break; case 3: //tag page $catObj = get_queried_object(); $html = $this->generateFiltersHtml($settings, $viewId, false, false, array('product_tag' => $catObj->term_id)); break; case 4: //brand page $catObj = get_queried_object(); $html = $this->generateFiltersHtml($settings, $viewId, false, false, array('product_brand' => $catObj->term_id)); break; case 5: //perfect brand page $catObj = get_queried_object(); $html = $this->generateFiltersHtml($settings, $viewId, false, false, array('pwb-brand' => $catObj->term_id)); break; case 6: //attribute page $catObj = get_queried_object(); $html = $this->generateFiltersHtml($settings, $viewId, false, false, array($catObj->taxonomy => $catObj->term_id)); break; case 7: //vendor page $html = $this->generateFiltersHtml( $settings, $viewId, false, false, array( 'vendors' => $this->getVendor() ) ); break; case 10: //shortcode and admin preview case 8: //product page $html = $this->generateFiltersHtml($settings, $viewId, false, true); break; case 12: //all pages $catId = false; if (is_product_category()) { $catObj = get_queried_object(); $catId = $catObj->term_id; } $html = $this->generateFiltersHtml($settings, $viewId, $catId, true); break; case 11: //brand page $catObj = get_queried_object(); $html = $this->generateFiltersHtml( $settings, $viewId, false, false, array( $catObj->taxonomy => $catObj->term_id ) ); break; } $this->assign('viewId', $viewId); $this->assign('html', $html); return parent::getContent('woofiltersHtml'); } private function getVendor() { if ( class_exists('WC_Vendors') ) { $vendor_shop = urldecode( get_query_var( 'vendor_shop' ) ); return WCV_Vendors::get_vendor_id( $vendor_shop ); } if ( is_plugin_active( 'dokan-lite/dokan.php' ) ) { $custom_store_url = dokan_get_option( 'custom_store_url', 'dokan_general', 'store' ); return get_query_var( $custom_store_url ); } } /** * Find display custom style status * * @param array $settings * * @return bool */ public function isCustomStyle( $settings = array() ) { $isCustomStyle = false; if ( $settings ) { $isCustomStyle = $this->getFilterSetting( $settings , 'disable_plugin_styles', false ); if ( $isCustomStyle ) { $isCustomStyle = false; } else { $isCustomStyle = true; } } return $isCustomStyle; } /** * Add comon styles and scripts. * * @param string $modPath */ public function addCommonAssets( $modPath, $settings = array() ) { $options = FrameWpf::_()->getModule( 'options' )->getModel( 'options' )->getAll(); FrameWpf::_()->addStyle( 'frontend.filters', $modPath . 'css/frontend.woofilters.css' ); FrameWpf::_()->addScript( 'frontend.filters', $modPath . 'js/frontend.woofilters.js' ); if ( isset( $options['content_accessibility'] ) && '1' === $options['content_accessibility']['value'] ) { FrameWpf::_()->addStyle( 'frontend.filters.accessibility', $modPath . 'css/frontend.woofilters.accessibility.css' ); } $forFilter = !empty($settings); $order = empty($settings['filters']['order']) ? '' : $settings['filters']['order']; if ( is_admin() || !$forFilter || strpos($order, 'mul_dropdown') ) { FrameWpf::_()->addStyle('frontend.multiselect', $modPath . 'css/frontend.multiselect.css'); FrameWpf::_()->addScript('frontend.multiselect', $modPath . 'js/frontend.multiselect.js'); $selectedTitle = ( isset($options['selected_title']['value']) && ''!==$options['selected_title']['value'] ) ? $options['selected_title']['value'] : 'selected'; FrameWpf::_()->addJSVar( 'frontend.multiselect', 'wpfMultySelectedTraslate', ' ' . esc_attr__( $selectedTitle, 'woo-product-filter' ) ); } $slider = ( is_admin() || !$forFilter || ( strpos($order, '"wpfPrice"') || strpos($order, '"slider"') ) ); FrameWpf::_()->getModule('templates')->loadJqueryUi($slider); } /** * Add assets to render html(shortcode and widget) * * @param string $modPath */ public function addRenderHtmlAssets( $modPath, $settings = array() ) { FrameWpf::_()->getModule('templates')->loadCoreJs(); $settings = $this->getFilterSetting($settings, 'settings', array()); $order = empty($settings['filters']['order']) ? '' : $settings['filters']['order']; $forFilter = !empty($settings); if ( is_admin() || !$forFilter || ( strpos($order, '"wpfPrice"') || strpos($order, '"slider"') ) ) { FrameWpf::_()->addScript('jquery-ui-slider'); } FrameWpf::_()->addScript('jquery-touch-punch'); $this->addCommonAssets($modPath, $settings); $options = FrameWpf::_()->getModule('options')->getModel('options')->getAll(); $loader = ( ( isset($options['loader_enable']) && isset($options['loader_enable']['value']) && !empty($options['loader_enable']['value']) ) || ( $this->getFilterSetting($settings, 'filter_loader_icon_onload_enable') == 1 ) || ( ( $this->getFilterSetting($settings, 'enable_overlay') == 1 ) && ( $this->getFilterSetting($settings, 'enable_overlay_icon') == 1 ) ) ); if ($loader) { FrameWpf::_()->addStyle('loaders', $modPath . 'css/loaders.css'); } FrameWpf::_()->addJSVar('frontend.filters', 'url', admin_url('admin-ajax.php')); if ($this->getFilterSetting($settings, 'disable_fontawesome_loading', false, 1) != 1) { FrameWpf::_()->getModule('templates')->loadFontAwesome(); } if ( isset($options['move_sidebar']) && isset($options['move_sidebar']['value']) && !empty($options['move_sidebar']['value']) ) { FrameWpf::_()->addStyle('move.sidebar.css', $modPath . 'css/move.sidebar.css'); } } /** * Add plugin custom styles. * * @param string $modPath * @param bool $isCustomStyle * * @return void */ public function addPluginCustomStyles( $modPath, $isCustomStyle ) { $params = ReqWpf::get( 'get' ); if ( $isCustomStyle && ( ! is_admin() || ( isset( $params['page'] ) && 'wpf-filters' === $params['page'] ) ) ) { FrameWpf::_()->addStyle( 'custom.filters', $modPath . 'css/custom.woofilters.css' ); } } protected function setUniqueBlockId( $key ) { self::$filterOrderKey = $key; self::$uniqueBlockId++; self::$blockId = 'wpfBlock_' . self::$uniqueBlockId; } //for now after render we run once filtering, in order to display products on custom page. public function renderProductsListHtml( $params ) { $html = '<div class="woocommerce wpfNoWooPage">'; $html .= '<p class="woocommerce-result-count"></p>'; $html .= '<ul class="products columns-4"></ul>'; $html .= '<nav class="woocommerce-pagination"></nav>'; if ( ReqWpf::getVar( 'wpf_skip' ) != '1' ) { $html .= '<script>jQuery(document).ready(function() { setTimeout(function() {jQuery("body").trigger("wpffiltering"); }, 1000); })</script>'; } $html .= '</div>'; return $html; } /** * Set existing individual filter items to appropriate properties * * @param array $order * @param array $prodCatId * @param array $querySettings */ public function setFilterExistsItems( $order, $prodCatId = false, $querySettings = array(), $settings = array()) { if (is_null(self::$filterExistsTerms)) { $module = $this->getModule(); $currentSettings = $this->getCurrentSettings(); $taxonomies = $module->getFilterTaxonomies($order, false, $currentSettings['settings']); $itemList = $module->getFilterExistsItems(null, $taxonomies, null, $prodCatId, $order, false, $currentSettings['settings'], $settings); self::$filterExistsTermsJS = isset( $itemList['existsTermsJS'] ) ? $itemList['existsTermsJS'] : false; self::$filterExistsTerms = isset($itemList['exists']) ? $itemList['exists'] : false; self::$filterExistsTermsWithotFiltering = isset($itemList['all']) ? $itemList['all'] : self::$filterExistsTerms; self::$filterExistsUsers = isset($itemList['existsUsers']) ? $itemList['existsUsers'] : array(); self::$filterExistsPrices = isset($itemList['existsPrices']) ? $itemList['existsPrices'] : array(); self::$currentFilterRecount = $module->isFiltered(false) ? $this->getFilterSetting($currentSettings['settings'], 'filter_recount', false) : true; } return self::$filterExistsTerms; } public function resetFilterExistsTerms() { self::$filterExistsTerms = null; } public function setFilterCss( $css ) { self::$filtersCss .= $css; } public function resetFiltersCss() { self::$filtersCss = ''; } public function setLeerFilter( $leer ) { self::$isLeerFilter = $leer; } public function generateFiltersHtml( $filterSettings, $viewId, $prodCatId = false, $noWooPage = false, $taxonomies = array() ) { $customCss = ''; if (!empty($filterSettings['settings']['css_editor'])) { $customCss = stripslashes(base64_decode($filterSettings['settings']['css_editor'])); unset($filterSettings['settings']['css_editor']); } if (!empty($filterSettings['settings']['js_editor'])) { $filterSettings['settings']['js_editor'] = stripslashes(base64_decode($filterSettings['settings']['js_editor'])); } $this->setCurrentSettings($filterSettings); $this->resetFiltersCss(); $settingsOriginal = $filterSettings; $filtersOrder = UtilsWpf::jsonDecode($filterSettings['settings']['filters']['order']); // determines if there are identical names of blocks that need to be added an index $filterName = array(); foreach ( $filtersOrder as $filter ) { $name = ( isset($filter['name']) ) ? $filter['name'] : ''; if ( '' !== $name ) { if ( in_array( $name, $filterName ) ) { $this->needIndex[] = $name; } else { $filterName[] = $name; } } } $buttonsPosition = ( !empty($filterSettings['settings']['main_buttons_position']) ) ? $filterSettings['settings']['main_buttons_position'] : 'bottom' ; $buttonsOrder = ( !empty($filterSettings['settings']['main_buttons_order']) ) ? $filterSettings['settings']['main_buttons_order'] : 'left' ; $showCleanButton = ( !empty($filterSettings['settings']['show_clean_button']) ) ? $filterSettings['settings']['show_clean_button'] : false ; $showFilteringButton = ( !empty($filterSettings['settings']['show_filtering_button']) ) ? $filterSettings['settings']['show_filtering_button'] : false ; $filterButtonWord = ( !empty($filterSettings['settings']['filtering_button_word']) ) ? $filterSettings['settings']['filtering_button_word'] : 'Filter' ; $clearButtonWord = ( $showCleanButton && !empty($filterSettings['settings']['show_clean_button_word']) ) ? $filterSettings['settings']['show_clean_button_word'] : 'Clear' ; $enableAjax = ( !empty($filterSettings['settings']['enable_ajax']) ) ? $filterSettings['settings']['enable_ajax'] : 0 ; $forceShowCurrentFilter = ( isset($filterSettings['settings']['force_show_current']) ) ? $filterSettings['settings']['force_show_current'] : 0 ; global $wp_query; $postPerPage = function_exists( 'wc_get_default_products_per_row' ) ? apply_filters( 'loop_shop_per_page', wc_get_default_products_per_row() * wc_get_default_product_rows_per_page() ) : get_option( 'posts_per_page' ); $options = FrameWpf::_()->getModule('options')->getModel('options')->getAll(); if ( isset($options['count_product_shop']) && isset($options['count_product_shop']['value']) && !empty($options['count_product_shop']['value']) ) { $postPerPage = $options['count_product_shop']['value']; } $paged = isset($wp_query->query_vars['paged']) ? $wp_query->query_vars['paged'] : 1; //get all link if (empty($this->getModule()->mainWCQuery)) { $base = esc_url_raw( add_query_arg( 'product-page', '%#%', false ) ); $format = '?product-page=%#%'; } else { $base = esc_url_raw( str_replace( 999999999, '%#%', remove_query_arg( 'add-to-cart', get_pagenum_link( 999999999, false ) ) )); $format = ''; } //get only base link, remove all query params $base = explode( '?', $base ); $base = $base[0]; if (!empty($format)) { $base .= $format; } $paginationBase = $this->getPaginationBase(); $settings = $this->getFilterSetting($settingsOriginal, 'settings', array()); $querySettings = array( 'posts_per_page' => $postPerPage, 'posts_per_row' => $this->getFilterSetting($settings, 'columns_product_shop', '', true), 'paged' => $paged, 'base' => $base, 'format ' => $format, 'page_id' => $this->wpfGetPageId(), 'paginate_base' => empty($paginationBase['base']) ? '' : $paginationBase['base'], 'paginate_type' => empty($paginationBase['type']) ? '' : $paginationBase['type'], ); $allProductsFiltering = $this->getFilterSetting($settings, 'all_products_filtering', false); if ($prodCatId) { $querySettings['product_category_id'] = $prodCatId; } if ($allProductsFiltering) { $prodCatId = false; } $isPro = FrameWpf::_()->isPro(); if (!$allProductsFiltering && !empty($taxonomies)) { foreach ($taxonomies as $tax => $value) { switch ($tax) { case 'product_tag': $querySettings['product_tag'] = $value; break; case 'product_brand': if ($isPro) { $querySettings['product_brand'] = $value; } break; case 'pwb-brand': $querySettings['pwb-brand'] = $value; break; case 'vendors': $querySettings['vendors'] = $value; break; default: if (!empty($value)) { $querySettings['tax_page'] = array('taxonomy' => $tax, 'term' => $value); } break; } } } $querySettingsStr = htmlentities(UtilsWpf::jsonEncode($querySettings), ENT_COMPAT); unset($filterSettings['settings']['styles']); $filterSettings = htmlentities(UtilsWpf::jsonEncode($filterSettings), ENT_COMPAT); $noWooPageData = ''; if ($noWooPage) { $noWooPageData = 'data-nowoo="true"'; } $isMobile = UtilsWpf::isMobile(); $filterId = 'wpfMainWrapper-' . $viewId; if ( 'right' === $buttonsOrder ) { $this->setFilterCss('#' . $filterId . ' .wpfFilterButtons:after{content:"";display:table;width:100%;clear:both;}'); $this->setFilterCss('#' . $filterId . ' .wpfFilterButton.wpfButton,#' . $filterId . ' .wpfClearButton.wpfButton{float:right;}'); } $paddingChildList = (int) $this->getFilterSetting( $settings, 'padding_child_list', false ); if ( $paddingChildList ) { $this->setFilterCss( "#{$filterId} .wpfFilterContent ul ul {padding-inline-start:{$paddingChildList}px;}" ); } $proAttributes = DispatcherWpf::applyFilters('getProAttributes', '', $settings); $defaultWCQuery = $this->getFilterSetting($settings, 'third_party_prefilter', false, true) ? $this->getModule()->defaultWCQuery : ''; $html = '<div class="wpfMainWrapper" id="' . $filterId . '" data-viewid="' . $viewId . '" data-filter="' . explode( '_', $viewId )[0] . ( $forceShowCurrentFilter ? '" data-force="' . $forceShowCurrentFilter : '' ) . '" data-settings="' . $querySettingsStr . '" data-default-query="' . ( empty( $defaultWCQuery ) || is_null( $defaultWCQuery ) ? '' : htmlentities( UtilsWpf::jsonEncode( $defaultWCQuery ), ENT_COMPAT ) ) . '" data-filter-settings="' . $filterSettings . '" ' . $noWooPageData . $proAttributes . '>'; $html = DispatcherWpf::applyFilters('addHtmlBeforeFilter', $html, $settings, $viewId); if ( ( 'top' === $buttonsPosition || 'both' === $buttonsPosition ) && ( $showFilteringButton || $showCleanButton ) ) { $html .= '<div class="wpfFilterButtons">'; if ($showFilteringButton) { $html .= '<button class="wpfFilterButton wpfButton">' . __($filterButtonWord, 'woo-product-filter') . '</button>'; } if ($showCleanButton) { $html .= '<button class="wpfClearButton wpfButton">' . __($clearButtonWord, 'woo-product-filter') . '</button>'; } $html .= '</div>'; } if ( ! empty( $settings['styles']['button_block_float'] ) ) { $html .= '<div class="wpfClear"></div>'; } $width = false; $units = false; if ($isMobile) { $width = $this->getFilterSetting($settings, 'filter_width_mobile', false, true); $units = $this->getFilterSetting($settings, 'filter_width_in_mobile', false, false, array('%', 'px')); } if ( !$width || !$units ) { $width = $this->getFilterSetting($settings, 'filter_width', '100', true); $units = $this->getFilterSetting($settings, 'filter_width_in', '%', false, array('%', 'px')); } $mobileBreakpointWidth = $this->getMobileBreakpointValue($settings); if ($mobileBreakpointWidth) { $width = '100'; $units = '%'; } $this->setFilterCss('#' . $filterId . '{position:relative;width:' . $width . $units . ';}'); $width = false; $units = false; if ($isMobile) { $width = $this->getFilterSetting($settings, 'filter_block_width_mobile', false, true); $units = $this->getFilterSetting($settings, 'filter_block_width_in_mobile', false, false, array('%', 'px')); } if ( !$width || !$units ) { $width = $this->getFilterSetting($settings, 'filter_block_width', '100', true); $units = $this->getFilterSetting($settings, 'filter_block_width_in', '%', false, array('%', 'px')); } if ($mobileBreakpointWidth) { $blockWidth = '100%'; } else { $blockWidth = $width . $units; } $blockHeight = $this->getFilterSetting($settingsOriginal['settings'], 'filter_block_height', false, true); $blockStyle = 'visibility:hidden; width:' . $blockWidth . '; float:left; ' . ( $blockHeight ? 'height:' . $blockHeight . 'px;overflow: hidden;' : '' ); $blockStyle = 'visibility:hidden; width:' . $blockWidth . ';' . ( '100%' == $blockWidth ? '' : 'float:left;' ) . ( $blockHeight ? 'height:' . $blockHeight . 'px;overflow: hidden;' : '' ); $this->setFilterCss('#' . $filterId . ' .wpfFilterWrapper {' . $blockStyle . '}'); $blockStyle = ''; if ($isPro) { $proView = FrameWpf::_()->getModule('woofilterpro')->getView(); } $this->setFilterExistsItems($filtersOrder, $prodCatId, $querySettings, $settings); $useTitleAsSlug = $this->getFilterSetting($settingsOriginal['settings'], 'use_title_as_slug', false); foreach ($filtersOrder as $key => $filter) { if ( empty($filter['settings']['f_enable']) || true !== $filter['settings']['f_enable'] ) { continue; } $this->setUniqueBlockId($key); $this->setLeerFilter(false); $filter = DispatcherWpf::applyFilters('controlFilterSettings', $filter); $filter['blockAttributes'] = empty($filter['blockAttributes']) ? '' : ' ' . $filter['blockAttributes']; if ($useTitleAsSlug) { $filter['blockAttributes'] .= ' data-title="' . $this->getFilterSetting($filter['settings'], 'f_title', '') . '"'; } $method = 'generate' . str_replace('wpf', '', $filter['id']) . 'FilterHtml'; if ('wpfCategory' !== $filter['id']) { if ( $isPro && method_exists($proView, $method) ) { $html .= $proView->{$method}($filter, $settingsOriginal, $blockStyle, $key, $viewId); } elseif (method_exists($this, $method)) { $html .= $this->{$method}($filter, $settingsOriginal, $blockStyle, $key); } } else { if ( ! $prodCatId && isset( $querySettings['product_category_id'] ) ) { $prodCatId = $querySettings['product_category_id']; } $html .= $this->{$method}($filter, $settingsOriginal, $blockStyle, $prodCatId, $key); } } if ( ( 'bottom' === $buttonsPosition || 'both' === $buttonsPosition ) && ( $showFilteringButton || $showCleanButton ) ) { $html .= '<div class="wpfFilterButtons">'; if ($showFilteringButton) { $html .= '<button class="wpfFilterButton wpfButton">' . esc_html__($filterButtonWord, 'woo-product-filter') . '</button>'; } if ($showCleanButton) { $html .= '<button class="wpfClearButton wpfButton">' . esc_html__($clearButtonWord, 'woo-product-filter') . '</button>'; } $html .= '</div>'; } if (!empty($settings['styles']['button_block_float'])) { $html .= '<div class="wpfClear"></div>'; } if ( $isPro && method_exists($proView, 'generateLoaderLayoutHtml') ) { $html .= $proView->generateLoaderLayoutHtml($options); } else { $this->setFilterCss('#' . $filterId . ' .wpfLoaderLayout {position:absolute;top:0;bottom:0;left:0;right:0;background-color: rgba(255, 255, 255, 0.9);z-index: 999;}'); $this->setFilterCss('#' . $filterId . ' .wpfLoaderLayout i {position:absolute;z-index:9;top:50%;left:50%;margin-top:-30px;margin-left:-30px;color:rgba(0,0,0,.9);}'); $html .= '<div class="wpfLoaderLayout"><i class="fa fa-spinner fa-pulse fa-3x fa-fw"></i></div>'; } //if loader enable on load if (!empty($settingsOriginal['settings']['filter_loader_icon_onload_enable'])) { $html .= $this->generateLoaderHtml($filterId, $settingsOriginal); } //if loader enable on filtering if (!empty($settingsOriginal['settings']['enable_overlay'])) { $html .= $this->generateOverlayHtml($settingsOriginal); } $html = DispatcherWpf::applyFilters('addHtmlAfterFilter', $html, $settings, $this->filter['id']); $html .= '</div>'; $html .= self::$filterExistsTermsJS; $html = '<style type="text/css" id="wpfCustomCss-' . $viewId . '">' . DispatcherWpf::applyFilters('addCustomCss', $customCss . self::$filtersCss, $settings, $filterId) . '</style>' . $html; $this->resetFilterExistsTerms(); return $html; } public function generateOverlayHtml( $settings ) { $settings = $this->getFilterSetting($settings, 'settings', array()); $overlayBackground = $this->getFilterSetting($settings, 'overlay_background', 'rgba(0,0,0,.5)'); $this->setFilterCss('#wpfOverlay {background-color:' . $overlayBackground . '!important;}'); $html = ''; $html .= '<div id="wpfOverlay">'; $html .= '<div id="wpfOverlayText">'; if ( !empty($settings['enable_overlay_word']) && !empty($settings['overlay_word']) ) { $html .= __($settings['overlay_word'], 'woo-product-filter'); } if (!empty($settings['enable_overlay_icon'])) { $colorPreview = $this->getFilterSetting($settings, 'filter_loader_icon_color', 'black'); $iconName = $this->getFilterSetting($settings, 'filter_loader_icon_name', 'default'); $iconNumber = $this->getFilterSetting($settings, 'filter_loader_icon_number', '0'); if (!FrameWpf::_()->isPro()) { $iconName = 'default'; } $html .= '<div class="wpfPreview">'; if ('custom' === $iconName) { $settings['is_overlay'] = true; $html = DispatcherWpf::applyFilters('getCustomLoaderHtml', $html, $settings); } elseif ( 'default' === $iconName || 'spinner' === $iconName ) { $html .= '<div class="woobewoo-filter-loader spinner"></div>'; } else { $this->setFilterCss('#wpfOverlay .woobewoo-filter-loader {color: ' . $colorPreview . ';}'); $html .= '<div class="woobewoo-filter-loader la-' . $iconName . ' la-2x">'; for ($i = 1; $i <= $iconNumber; $i++) { $html .= '<div></div>'; } $html .= '</div>'; } $html .= '</div>'; } $html .= '</div>'; $html .= '</div>'; return $html; } public function generateIconCloseOpenTitleHtml( $filter, $filterSettings, $showTitle ) { if ( empty($filter['settings']) || empty($filterSettings['settings']['hide_filter_icon']) ) { return ''; } // deprecated fallback for previous settings if (UtilsWpf::isMobile() && empty($showTitle)) { $showTitle = $this->getFilterSetting($filter['settings'], 'f_enable_title'); } if ('yes_open' === $showTitle) { $iconClass = DispatcherWpf::applyFilters('getIconHtml', 'fa-minus', 'title_icons', $filterSettings); $icon = '<i class="fa ' . $iconClass . ' wpfTitleToggle"></i>'; } elseif ('yes_close' === $showTitle) { $iconClass = DispatcherWpf::applyFilters('getIconHtml', 'fa-plus', 'title_icons', $filterSettings); $icon = '<i class="fa ' . $iconClass . ' wpfTitleToggle"></i>'; } else { $icon = ''; } return $icon; } public function generateDescriptionHtml( $filter ) { $description = $this->getFilterSetting($filter['settings'], 'f_description', false); if ($description) { $html = '<div class="wfpDescription">' . __($description, 'woo-product-filter') . '</div>'; } else { $html = ''; } return $html; } public function generateBlockClearHtml( $filter, $filterSettings ) { $html = ''; if ($this->getFilterSetting($filterSettings['settings'], 'show_clean_block', false)) { $clearWord = $this->getFilterSetting($filterSettings['settings'], 'show_clean_block_word', false); $clearWord = $clearWord ? $clearWord : esc_attr__('clear', 'woo-product-filter'); $html = ' <label class="wpfBlockClear">' . esc_html($clearWord) . '</label>'; } return $html; } public function generateFilterHeaderHtml( $filter, $filterSettings, $noActive = true ) { $showTitle = $this->getFilterSetting( $filter['settings'], 'f_enable_title' . ( UtilsWpf::isMobile() ? '_mobile' : '' ) ); if ( ! $noActive && 'yes_close' === $showTitle ) { $showTitle = 'yes_open'; } // deprecated fallback for previous settings if (UtilsWpf::isMobile() && empty($showTitle)) { $showTitle = $this->getFilterSetting($filter['settings'], 'f_enable_title'); } $showCustomTags = $this->getFilterSetting($filter['settings'], 'f_custom_tags', false); $headerTag = $this->getFilterSetting($filter['settings'], 'f_custom_tags_settings[header]', 0); $headerTag = $headerTag && $showCustomTags ? FrameWpf::_()->getModule('woofilters')->getFilterTagsList()[$headerTag] : 'div'; $titleMobileBreakpointData = $this->getMobileBreakpointOptionData($filter, $filterSettings); if ($titleMobileBreakpointData) { $title = $this->getFilterSetting($filter['settings'], 'f_title', false); } else { $title = 'no' == $showTitle ? false : $this->getFilterSetting($filter['settings'], 'f_title', false); } $html = ''; if ($title) { $icon = $this->generateIconCloseOpenTitleHtml( $filter, $filterSettings, $showTitle ); $html .= '<div class="wpfFilterTitle" ' . $titleMobileBreakpointData . '><' . $headerTag . ' class="wfpTitle'; $html .= ( (int) $this->getFilterSetting($filterSettings['settings'], 'hide_filter_icon', 0) ? ' wfpClickable' : '' ); $html .= '">'; $html .= esc_html__($title, 'woo-product-filter'); $html .= '</' . $headerTag . '>'; $html .= $icon; } $html .= $this->generateBlockClearHtml($filter, $filterSettings); if ($title) { $html .= '</div>'; } $html .= '<div class="wpfFilterContent' . ( 'yes_close' == $showTitle ? ' wpfBlockAnimated wpfHide' : '' ) . '"'; $html .= '>'; return $html; } public function getMobileBreakpointOptionData( $filter, $filterSettings ) { $titleMobileBreakpointData = ''; $mobileBreakpointWidth = $this->getMobileBreakpointValue($filterSettings['settings']); if ($mobileBreakpointWidth) { $showTitleDesctop = $this->getFilterSetting( $filter['settings'], 'f_enable_title', 'no' ); $showTitleMobile = $this->getFilterSetting( $filter['settings'], 'f_enable_title_mobile', 'no' ); if ('no' != $showTitleDesctop || 'no' != $showTitleMobile) { $titleMobileBreakpointData = ' data-show-on-mobile="' . esc_html($showTitleMobile) . '" data-show-on-desctop="' . esc_html($showTitleDesctop) . '" '; } } return $titleMobileBreakpointData; } public function generatePriceFilterHtml( $filter, $filterSettings, $blockStyle, $key = 1, $viewId = '' ) { // Find min and max price in current result set. $prices = self::$filterExistsPrices; $settings = $this->getFilterSetting($filter, 'settings', array()); $filterName = 'wpf_min_price,wpf_max_price,tax'; $settings['minPrice'] = '0' === $prices->wpfMinPrice ? '0.01' : $prices->wpfMinPrice; $settings['maxPrice'] = $prices->wpfMaxPrice; $noActive = ( ReqWpf::getVar('wpf_min_price', 'all', -1) >= 0 && ReqWpf::getVar('wpf_max_price', 'all', -1) >= 0 ) ? '' : 'wpfNotActive'; $html = '<div class="wpfFilterWrapper ' . $noActive . '"' . $this->setFitlerId() . $this->setCommonFitlerDataAttr($filter, $filterName, '') . ' data-price-skin="default' . '" data-minvalue="' . $prices->wpfMinPrice . '" data-maxvalue="' . $prices->wpfMaxPrice . ( ( isset( $prices->tax ) ) ? '" data-tax="' . $prices->tax : '' ) . '"' . $filter['blockAttributes'] . '>' . '<div class="wpfVisibleBufferMin wpfVisibilityHidden"></div>' . '<div class="wpfVisibleBufferMax wpfVisibilityHidden"></div>' . $this->generateFilterHeaderHtml($filter, $filterSettings, $noActive) . $this->generateDescriptionHtml($filter) . '<div id="wpfSliderRange" class="wpfPriceFilterRange"></div>' . $this->generatePriceInputsHtml($settings) . '</div>'; $html .= '</div>'; return $html; } public function generatePriceInputsHtml( $settings ) { $dataStep = 1; if (class_exists('frameWcu')) { $currencySwitcher = frameWcu::_()->getModule('currency'); if (isset($currencySwitcher)) { $currentCurrency = $currencySwitcher->getCurrentCurrency(); $cryptoCurrencyList = $currencySwitcher->getCryptoCurrencyList(); if (array_key_exists($currentCurrency, $cryptoCurrencyList)) { $dataStep = 0.001; } } } if ( !isset($settings['minValue']) || is_null($settings['minValue']) ) { $settings['minValue'] = $settings['minPrice']; } if ( !isset($settings['maxValue']) || is_null($settings['maxValue']) || -1 === $settings['maxValue'] ) { $settings['maxValue'] = $settings['maxPrice']; } $dec = $this->getFilterSetting($settings, 'decimal', 0, true); if (FrameWpf::_()->isPro()) { $settings = DispatcherWpf::applyFilters('checkPriceArgs', $settings); } if ($this->getFilterSetting($settings, 'f_currency_show_as', '') === 'symbol') { $currencyShowAs = get_woocommerce_currency_symbol(); } else { $currencyShowAs = get_woocommerce_currency(); } if ($this->getFilterSetting($settings, 'f_currency_position', '') === 'before') { $currencySymbolBefore = '<span class="wpfCurrencySymbol">' . $currencyShowAs . '</span>'; $currencySymbolAfter = ''; } else { $currencySymbolAfter = '<span class="wpfCurrencySymbol">' . $currencyShowAs . '</span>'; $currencySymbolBefore = ''; } if ( !empty($settings['f_price_tooltip_show_as']) ) { $priceTooltip['class'] = 'wpfPriceTooltipShowAsText'; $priceTooltip['readonly'] = 'readonly'; } $priceTooltip['class'] = isset($priceTooltip['class']) ? $priceTooltip['class'] : ''; $priceTooltip['readonly'] = isset($priceTooltip['readonly']) ? $priceTooltip['readonly'] : ''; $hideInputs = ( $this->getFilterSetting($settings, 'f_show_inputs') ? '' : ' wpfHidden' ); return '<div class="wpfPriceInputs' . $hideInputs . '">' . $currencySymbolBefore . '<input ' . $priceTooltip['readonly'] . ' type="number' . '" min="' . $settings['minPrice'] . '" max="' . ( $settings['maxPrice'] - 1 ) . '" id="wpfMinPrice' . '" class="wpfPriceRangeField ' . $priceTooltip['class'] . '" value="' . number_format($settings['minValue'], $dec, '.', '') . '" />' . '<span class="wpfFilterDelimeter"> - </span>' . '<input ' . $priceTooltip['readonly'] . ' type="number" ' . ' min="' . $settings['minPrice'] . '" max="' . $settings['maxPrice'] . '" id="wpfMaxPrice"' . ' class="wpfPriceRangeField ' . $priceTooltip['class'] . '" value="' . number_format($settings['maxValue'], $dec, '.', '') . '" /> ' . '<input ' . $priceTooltip['readonly'] . ' type="hidden" id="wpfDataStep" value="' . $dataStep . '" />' . $currencySymbolAfter . '</div>'; } public function getFilterLayout( $settings, $options, $isVertical = true, $cnt = 1 ) { $addClass = ''; if (isset($settings['f_layout'])) { $isVertical = $this->getFilterSetting($settings, 'f_layout', 'ver') == 'ver'; if ($isVertical) { $cnt = $this->getFilterSetting($settings, 'f_ver_columns', 1, true); } } elseif ($isVertical) { if ($this->getFilterSetting($options['settings'], 'display_items_in_a_row', false)) { $cnt = $this->getFilterSetting($options['settings'], 'display_cols_in_a_row', 1, true); } } if ($isVertical) { if ($cnt > 1) { $addClass = ' wpfFilterLayoutVer'; } } else { $addClass = ' wpfFilterLayoutHor'; } return array('is_ver' => $isVertical, 'cnt' => $cnt, 'class' => $addClass); } public function generatePriceRangeFilterHtml( $filter, $filterSettings, $blockStyle, $key = 1, $viewId = '' ) { $settings = $this->getFilterSetting($filter, 'settings', array()); $layout = $this->getFilterLayout($settings, $filterSettings); $type = $this->getFilterSetting($settings, 'f_frontend_type', 'list'); $underOver = FrameWpf::_()->isPro() && $this->getFilterSetting($settings, 'f_under_over', false); $defaultRange = ''; $module = FrameWpf::_()->getModule('woofilters'); if ($filter['settings']['f_range_by_hands']) { $ranges = array_chunk(explode(',', $this->getFilterSetting($settings, 'f_range_by_hands_values', '')), 2); $htmlOpt = $this->generatePriceRangeOptionsHtml($filter, $ranges, $layout); $default = explode(',', $this->getFilterSetting($settings, 'f_range_by_hands_default', '')); if ( count($default) == 2 && ( 'i' != $default[0] || 'i' != $default[1] ) ) { $defaultRange = ' data-default="' . ( 'i' == $default[0] ? '' : $module->getCurrencyPrice($default[0]) ) . ',' . ( 'i' == $default[1] ? '' : $module->getCurrencyPrice($default[1]) ) . '"'; } } elseif ($filter['settings']['f_range_automatic']) { $prices = self::$filterExistsPrices; $minPrice = '0' === $prices->wpfMinPrice && !$underOver ? '0.01' : $prices->wpfMinPrice; $maxPrice = $prices->wpfMaxPrice; $step = !empty($filter['settings']['f_step']) ? $filter['settings']['f_step'] : 50; $priceRange = $maxPrice - $minPrice; $countElements = ceil($priceRange / $step); if ($countElements > 100) { $step = ceil($priceRange / 1000) * 10; $countElements = ceil($priceRange / $step); } if ( 1 == $countElements ) { $ranges[0] = array( ( $underOver ? 'i' : $minPrice ), $maxPrice ); } else { $ranges = array(); $priceTempOld = 0; for ( $i = 0; $i < $countElements; $i ++ ) { if ( 0 === $i ) { $priceTemp = $minPrice + $step; $ranges[ $i ] = array( ( $underOver ? 'i' : $minPrice ), $priceTemp - 0.01 ); $priceTempOld = $priceTemp; } elseif ( ( $priceTempOld + $step ) < $maxPrice ) { $priceTemp = $priceTempOld + $step; $ranges[ $i ] = array( $priceTempOld, $priceTemp - 0.01 ); $priceTempOld = $priceTemp; } else { $ranges[ $i ] = array( $priceTempOld, ( $underOver ? 'i' : $maxPrice ) ); } } } $htmlOpt = $this->generatePriceRangeOptionsHtml($filter, $ranges, $layout); } if (!$htmlOpt) { $htmlOpt = esc_html__('Price range filter is empty. Please setup filter correctly.', 'woo-product-filter'); } $noActive = ReqWpf::getVar('wpf_min_price') && ReqWpf::getVar('wpf_max_price') ? '' : 'wpfNotActive'; $html = '<div class="wpfFilterWrapper ' . $noActive . ( empty($defaultRange) ? '' : ' wpfPreselected' ) . '"' . $this->setFitlerId() . $this->setCommonFitlerDataAttr($filter, 'wpf_min_price,wpf_max_price,tax', $filter['settings']['f_frontend_type']) . ' data-radio="' . ( 'list' == $type ? '1' : '0' ) . '"' . $defaultRange . ( ( isset( $prices->tax ) ) ? ' data-tax="' . $prices->tax . '"' : '' ) . $filter['blockAttributes'] . '>'; $html .= $this->generateFilterHeaderHtml($filter, $filterSettings, $noActive); $html .= $this->generateDescriptionHtml($filter); $html .= '<div class="wpfCheckboxHier">'; if ('list' === $type) { $maxHeight = $this->getFilterSetting($settings, 'f_max_height', 0, true); if ($maxHeight > 0) { $this->setFilterCss('#' . self::$blockId . ' .wpfFilterVerScroll {max-height:' . $maxHeight . 'px;}'); } $html .= '<ul class="wpfFilterVerScroll' . $layout['class'] . '">'; } $html .= $htmlOpt; if ('list' === $type) { $html .= '</ul>'; } $html .= '</div>';//end wpfCheckboxHier $html .= '</div>';//end wpfFilterContent $html .= '</div>'; //end wpfFilterWrapper return $html; } public function generateSortByFilterHtml( $filter, $filterSettings, $blockStyle, $key = 1, $viewId = '' ) { $optionsAll = FrameWpf::_()->getModule( 'woofilters' )->getModel( 'woofilters' )->getFilterLabels( 'SortBy' ); $settings = $this->getFilterSetting( $filter, 'settings', array() ); foreach ( $optionsAll as $key => $value ) { $optionsAll[ $key ] = $this->getFilterSetting( $settings, 'f_option_labels[' . $key . ']', $value ); } $options = $this->getFilterSetting( $settings, 'f_options[]', false ); $options = explode( ',', $options ); if ( ReqWpf::getVar('orderby') ) { $optionsSelected = ReqWpf::getVar('orderby'); } else { $optionsSelected = $this->getFilterUrlData('pr_sortby'); } $frontendTypes = array('dropdown', 'radio'); $type = $this->getFilterSetting($settings, 'f_frontend_type', 'dropdown', false, DispatcherWpf::applyFilters('getFrontendFilterTypes', $frontendTypes, $filter['id'])); $filter['settings']['f_frontend_type'] = $type; $productSortBy = array(); $sortBySelected = array($optionsSelected); $obj = new stdClass(); foreach ($options as $key => $option) { if (!empty($option)) { $obj->term_id = $option; $obj->slug = $option; $obj->name = $optionsAll[$option]; $productSortBy[] = clone $obj; } } $noActive = $optionsSelected ? '' : 'wpfNotActive'; $html = '<div class="wpfFilterWrapper ' . $noActive . '"' . $this->setFitlerId() . $this->setCommonFitlerDataAttr($filter, 'orderby', '') . ' data-radio="' . ( 'radio' === $type ? '1' : '0' ) . '"' . ' data-display-type="' . $type . '"' . ' data-first-instock="' . ( $this->getFilterSetting($settings, 'f_first_instock', false) ? 1 : 0 ) . '"' . $filter['blockAttributes'] . '>'; $html .= $this->generateFilterHeaderHtml($filter, $filterSettings, $noActive); $html .= $this->generateDescriptionHtml($filter); $perPage = ''; $perPageLeft = false; if ($this->getFilterSetting($settings, 'f_show_per_page', false)) { $perPageList = explode(',', $this->getFilterSetting($settings, 'f_per_page_list', '48,24,12')); $perPageLeft = $this->getFilterSetting($settings, 'f_per_page_position', 'left') == 'left'; $perPage = '<select class="wpfPerPageDD">'; if ( ReqWpf::getVar('wpf_count') ) { $countSelected = ReqWpf::getVar('wpf_count'); } else { $countSelected = empty($perPageList) ? 0 : $perPageList[0]; } foreach ($perPageList as $l) { $n = (int) trim($l); if (!empty($n)) { $perPage .= '<option value="' . $n . '"' . ( $n == $countSelected ? ' selected' : '' ) . '>' . $n . '</option>'; } } $perPage .= '</select>'; $this->setFilterCss('#' . self::$blockId . ' .wpfFilterContent {display:flex}'); $this->setFilterCss('#' . self::$blockId . ' .wpfPerPageDD {margin-' . ( $perPageLeft ? 'right' : 'left' ) . ': 2px;}'); } self::$leer = true; $htmlOpt = $this->generateTaxonomyOptionsHtml( $productSortBy, $sortBySelected, $filter ); switch ($type) { case 'radio': $html .= '<ul class="wpfFilterVerScroll">' . $htmlOpt . '</ul>'; break; case 'dropdown': $html .= ( $perPageLeft ? $perPage : '' ) . '<select>' . $htmlOpt . '</select>' . ( $perPageLeft ? '' : $perPage ); break; case 'mul_dropdown': $settings['f_single_select'] = true; $settings['f_hide_checkboxes'] = true; $settings['f_dropdown_first_option_text'] = $productSortBy[0]->name; $html .= $this->getMultiSelectHtml( $htmlOpt, $settings ); break; } $html .= '</div>';//end wpfFilterContent $html .= '</div>'; //end wpfFilterWrapper return $html; } public function notChangeCategoryCount ( $tax ) { if (is_array($tax)) { foreach ($tax as $key => $value) { if ( 'product_cat' == $value ) { unset($tax[$key]); break; } } } return $tax; } public function generateCategoryFilterHtml( $filter, $filterSettings, $blockStyle, $prodCatId = false, $key = 1, $viewId = '' ) { $settings = $this->getFilterSetting($filter, 'settings', array()); $labels = FrameWpf::_()->getModule('woofilters')->getModel('woofilters')->getFilterLabels('Category'); $hidden_categories = isset($settings['f_hidden_categories']) ? $settings['f_hidden_categories'] : false; $includeCategoryId = ( !empty($settings['f_mlist[]']) ) ? explode(',', $settings['f_mlist[]']) : false; $includeCategoryChildren = $this->getFilterSetting($settings, 'f_mlist_with_children', false); $excludeIds = !empty($settings['f_exclude_terms']) ? $settings['f_exclude_terms'] : false; $frontendTypes = array('list', 'dropdown'); $type = $hidden_categories ? 'list' : $this->getFilterSetting($settings, 'f_frontend_type', 'list', false, DispatcherWpf::applyFilters('getFrontendFilterTypes', $frontendTypes, $filter['id'])); $isHierarchical = !empty($settings['f_show_hierarchical']) ? true : false; $hideChild = !empty($settings['f_hide_taxonomy']) ? true : false; $isExtendParentFiltering = !empty($settings['f_extend_parent_filtering']) ? true : false; $isIncludeChildren = $this->findTaxonomyIncludeChildrenStatus($hideChild, $isExtendParentFiltering, $type); $hideEmpty = $this->getFilterSetting($settings, 'f_hide_empty', false); $hideEmptyActive = $hideEmpty && $this->getFilterSetting($settings, 'f_hide_empty_active', false); $useSlugs = $this->getFilterSetting($filterSettings['settings'], 'use_category_slug', false); $allProductsFiltering = $this->getFilterSetting($filterSettings['settings'], 'all_products_filtering', false); $taxonomy = 'product_cat'; if (!empty($includeCategoryId) && $includeCategoryChildren) { $includeCategoryId = $this->getChildrenOfIncludedCategories($taxonomy, $includeCategoryId); } $args = array( 'parent' => 0, 'hide_empty' => $hideEmpty, 'include' => $includeCategoryId, ); $isCustomOrder = $includeCategoryId && !empty($settings['f_order_custom']); $order = !$isCustomOrder && !empty($settings['f_sort_by']) ? $settings['f_sort_by'] : 'default'; $isDefaultOrder = ( 'default' === $order ); if ($isCustomOrder || !$isDefaultOrder) { $args = array_merge($args, [ 'orderby' => ( $isCustomOrder ? 'include' : 'name' ), 'order' => ( $isDefaultOrder ? 'asc' : $order ), 'sort_as_numbers' => ( $isDefaultOrder ? false : $this->getFilterSetting($settings, 'f_sort_as_numbers', false) ), ]); } if ($hideChild) { $args['only_parent'] = $hideChild; } $showAllCats = $this->getFilterSetting($settings, 'f_show_all_categories', false); list($showedTerms, $countsTerms, $showFilter, $allTerms) = $this->getShowedTerms($taxonomy, $showAllCats); if ($this->getFilterSetting($settings, 'f_show_count', false) && !$this->getFilterSetting($settings, 'f_show_count_parent_with_children', false)) { add_filter('woocommerce_change_term_counts', array($this, 'notChangeCategoryCount')); } $onlyNeeded = false; if (empty($includeCategoryId) && !$allProductsFiltering && !empty($allTerms) && empty($args['only_parent'])) { $args['include'] = $allTerms; $onlyNeeded = true; } $productCategory = $this->getTaxonomyHierarchy($taxonomy, $args); if (!empty($args['only_parent'])) { foreach ($productCategory as $id => $cat) { if (!empty($cat->children)) { $productCategory[$id]->children = array(); } } } remove_filter('woocommerce_change_term_counts', array($this, 'notChangeCategoryCount')); if (!$productCategory) { return ''; } if ( ( $includeCategoryId || $onlyNeeded ) && $isHierarchical ) { $productCategory = $this->getCustomHierarchicalCategories($productCategory); } $filter['settings']['f_frontend_type'] = $type; $isMulti = ( 'multi' == $type || 'mul_dropdown' == $type ); $defFilterName = $this->getFilterSetting($filter, 'name', 'wpf_filter_cat'); $filterName = 'wpf_filter_cat'; if (!$isIncludeChildren) { $filterName .= '_list'; } $filterName .= '_' . $key; $defFilterName .= '_' . $key; if ($useSlugs) { $filterName .= 's'; } $defSelected = $this->getFilterUrlData($filterName, $defFilterName); $catSelected = $defSelected; if ($catSelected) { if ($catSelected == $this->getFilterSetting($settings, 'f_select_default_id')) { $filter['is_ids'] = true; } elseif ($useSlugs) { $filter['is_slugs'] = true; } $ids = explode('|', $catSelected); if (count($ids) <= 1) { $ids = explode(',', $catSelected); } $catSelected = $ids; } elseif ( $hidden_categories && $includeCategoryId ) { $catSelected = $includeCategoryId; $filter['is_ids'] = true; } else { $catSelected = array(); } $currentCategoryId = 0; if ( $this->getFilterSetting( $settings, 'f_hide_page_category', false ) ) { $path = parse_url( ReqWpf::getVar( 'REQUEST_URI', 'server' ), PHP_URL_PATH ); $parts = explode( '/', $path ); $slug = $parts[ count( $parts ) - 1 ]; $category = get_term_by( 'slug', $slug, 'product_cat' ); if ($category) { $currentCategoryId = $category->term_id; } } $setCurCat = false; if ($prodCatId && $this->getFilterSetting($settings, 'f_set_page_category', false)) { $catSelected[] = $prodCatId; if ($this->getFilterSetting($settings, 'f_set_parent_page_category', false)) { $catSelected = array_merge($catSelected, get_ancestors($prodCatId, 'product_cat')); } /*$childs = get_term_children($prodCatId, 'product_cat'); if (is_array($childs)) { $catSelected = array_merge($catSelected, $childs); }*/ $setCurCat = true; } $layout = $this->getFilterLayout($settings, $filterSettings); $inLineClass = $layout['class']; $htmlOpt = ''; if ($defSelected && !$hideEmptyActive) { $showedTerms = $allTerms; $showFilter = true; } if ( in_array($type, $frontendTypes) || $isMulti ) { self::$leer = true; $htmlOpt = $this->generateTaxonomyOptionsHtml( $productCategory, $catSelected, $filter, $excludeIds, '', $layout, $includeCategoryId, $showedTerms, $countsTerms, 0, $currentCategoryId ); if ( 'list' === $type || 'multi' === $type ) { $maxHeight = $this->getFilterSetting($settings, 'f_max_height', 0, true); if ($maxHeight > 0) { $this->setFilterCss('#' . self::$blockId . ' .wpfFilterVerScroll {max-height:' . $maxHeight . 'px;}'); } $htmlOpt = '<ul class="wpfFilterVerScroll' . $inLineClass . '">' . $htmlOpt . '</ul>'; } elseif ('dropdown' === $type) { $htmlOpt = '<select><option value="" data-slug="">' . esc_html__($this->getFilterSetting($settings, 'f_dropdown_first_option_text', __('Select all', 'woo-product-filter')), 'woo-product-filter') . '</option>' . $htmlOpt . '</select>'; } elseif ('mul_dropdown' === $type) { $htmlOpt = $this->getMultiSelectHtml( $htmlOpt, $settings ); } } else { $htmlOpt = DispatcherWpf::applyFilters('getTaxonomyOptionsHtml', $htmlOpt, array( 'type' => $type, 'settings' => $filter, 'terms' => $productCategory, 'selected' => $catSelected, 'showed' => $showedTerms, 'counts' => $countsTerms, 'excludes' => $excludeIds, 'includes' => $includeCategoryId, 'display' => $layout, 'class' => $inLineClass )); } $noActive = $defSelected || $setCurCat ? '' : 'wpfNotActive'; $noActive = $hidden_categories ? 'wpfHidden' : $noActive; $preselected = $hidden_categories ? ' wpfPreselected' : ''; $blockStyle = ( !$showFilter || ( !$showAllCats && self::$isLeerFilter ) ? 'display:none;' : '' ) . $blockStyle; if (!empty($blockStyle)) { $this->setFilterCss('#' . self::$blockId . ' {' . $blockStyle . '}'); } $logic = $this->getFilterSetting($settings, 'f_multi_logic', 'or'); $notIds = ''; $notValues = ''; if ($hidden_categories) { if (!$includeCategoryId && $excludeIds) { $logic = 'not'; $notValues = '" data-not-ids="' . esc_attr($excludeIds); } } $showCount = $this->getFilterSetting($settings, 'f_show_count', false) ? ' wpfShowCount' : ''; $hierarchical = $isHierarchical ? 'true' : 'false'; //$iniqId = empty($filter['uniqId']) ? '' : $filter['uniqId']; $html = '<div class="wpfFilterWrapper ' . $noActive . $showCount . $preselected . '"' . $this->setFitlerId() . $this->setCommonFitlerDataAttr($filter, $filterName, $type) . //' data-uniq-id="' . $iniqId . ' data-radio="' . ( 'list' === $type ? '1' : '0' ) . '" data-query-logic="' . $logic . $notValues . '" data-logic-hierarchical="' . $this->getFilterSetting($settings, 'f_multi_logic_hierarchical', 'any') . '" data-query-children="' . ( $isIncludeChildren ? '1' : '0' ) . '" data-show-hierarchical="' . $hierarchical . '" data-taxonomy="product_cat' . '" data-hide-active="' . ( $hideEmptyActive ? '1' : '0' ) . '" data-show-all="' . ( (int) $showAllCats ) . '" data-use-slugs="' . ( $useSlugs ? '1' : '0' ) . '"' . $filter['blockAttributes'] . '>'; $html .= $this->generateFilterHeaderHtml($filter, $filterSettings, $noActive); $html .= $this->generateDescriptionHtml($filter); if ( 'list' === $type && $this->getFilterSetting($settings, 'f_show_search_input', false) ) { $html .= '<div class="wpfSearchWrapper"><input class="wpfSearchFieldsFilter passiveFilter" type="text" placeholder="' . esc_html__($this->getFilterSetting($settings, 'f_search_label', $labels['search']), 'woo-product-filter') . '"' . ( $this->getFilterSetting($settings, 'f_unfolding_by_search', false) ? ' data-unfolding="1"' : '' ) . ( $this->getFilterSetting($settings, 'f_collapse_by_delete', false) ? ' data-collapse-search="1"' : '' ) . '></div>'; } $html .= '<div class="wpfCheckboxHier">'; $html .= $htmlOpt; $html .= '</div>';//end wpfCheckboxHier $html .= '</div>';//end wpfFilterContent $html .= '</div>';//end wpfFilterWrapper return $html; } public function getCustomHierarchicalCategories( $productCategory ) { $moveCat = array(); foreach ($productCategory as $id => $cat) { $parentId = $cat->parent; if (0 != $parentId) { if (isset($productCategory[$parentId])) { $moveCat[$id] = $parentId; } } } while (count($moveCat) > 0) { reset($moveCat); $id = key($moveCat); do { $found = array_search($id, $moveCat); if ($found) { $id = $found; } } while ($found); $parentId = $moveCat[$id]; $parent = $productCategory[$parentId]; if ( property_exists($parent, 'children') && is_array($parent->children) ) { if (!isset($parent->children[$id])) { $parent->children[$id] = $productCategory[$id]; } } else { $parent->children = array($id => $productCategory[$id]); } $productCategory[$parentId] = $parent; unset($productCategory[$id], $moveCat[$id]); } return $productCategory; } /** * Generate custom taxonomy filter for a specific plugin * * @link https://wordpress.org/plugins/perfect-woocommerce-brands/ * * @param array $filter * @param array $filterSettingss * @param string $blockStyles * @param int $keys * @param int $viewIds * * @return string */ public function generatePerfectBrandFilterHtml( $filter, $filterSettings, $blockStyle, $key = 1, $viewId = '' ) { $settings = $this->getFilterSetting($filter, 'settings', array()); $labels = FrameWpf::_()->getModule('woofilters')->getModel('woofilters')->getFilterLabels('PerfectBrand'); $hiddenBrands = $this->getFilterSetting($settings, 'f_hidden_brands', false); $includeBrandId = ( !empty($settings['f_mlist[]']) ) ? explode(',', $settings['f_mlist[]']) : false; $includeBrandChildren = $this->getFilterSetting($settings, 'f_mlist_with_children', false); $isHierarchical = $this->getFilterSetting($settings, 'f_show_hierarchical', false); $frontendTypes = array('list', 'dropdown', 'mul_dropdown'); $type = $hiddenBrands ? 'list' : $this->getFilterSetting($settings, 'f_frontend_type', 'list', false, DispatcherWpf::applyFilters('getFrontendFilterTypes', $frontendTypes, $filter['id'])); $excludeIds = !empty($settings['f_exclude_terms']) ? $settings['f_exclude_terms'] : false; $hideChild = !empty($settings['f_hide_taxonomy']) ? true : false; $isIncludeChildren = $this->findTaxonomyIncludeChildrenStatus($hideChild, false, $type); $hideEmpty = $this->getFilterSetting($settings, 'f_hide_empty', false); $hideEmptyActive = $hideEmpty && $this->getFilterSetting($settings, 'f_hide_empty_active', false); $allProductsFiltering = $this->getFilterSetting($filterSettings['settings'], 'all_products_filtering', false); $taxonomy = 'pwb-brand'; if (!empty($includeBrandId) && $includeBrandChildren) { $includeBrandId = $this->getChildrenOfIncludedCategories($taxonomy, $includeBrandId); } $args = array( 'parent' => 0, 'hide_empty' => $hideEmpty, 'include' => $includeBrandId, ); $isCustomOrder = $includeBrandId && !empty($settings['f_order_custom']); $order = !$isCustomOrder && !empty($settings['f_sort_by']) ? $settings['f_sort_by'] : 'default'; $isDefaultOrder = ( 'default' === $order ); if ($isCustomOrder || !$isDefaultOrder) { $args = array_merge($args, [ 'orderby' => ( $isCustomOrder ? 'include' : 'name' ), 'order' => ( $isDefaultOrder ? 'asc' : $order ), 'sort_as_numbers' => ( $isDefaultOrder ? false : $this->getFilterSetting($settings, 'f_sort_as_numbers', false) ), ]); } if ($hideChild) { $args['only_parent'] = $hideChild; } $showAllBrands = $this->getFilterSetting($settings, 'f_show_all_brands', false); list($showedTerms, $countsTerms, $showFilter, $allTerms) = $this->getShowedTerms($taxonomy, $showAllBrands); $onlyNeeded = false; if (!$allProductsFiltering && !empty($allTerms)) { $args['include'] = empty($includeBrandId) ? $allTerms : array_intersect($allTerms, $includeBrandId); $onlyNeeded = true; } $productBrand = $this->getTaxonomyHierarchy($taxonomy, $args); if (!$productBrand) { return ''; } if ( ( $includeBrandId || $onlyNeeded ) && $isHierarchical ) { $productBrand = $this->getCustomHierarchicalCategories($productBrand); } $filter['settings']['f_frontend_type'] = $type; $isMulti = ( 'multi' == $type ); $filterName = 'wpf_filter_pwb'; if (!$isIncludeChildren) { $filterName .= '_list'; } $filterName .= '_' . $key; $defSelected = $this->getFilterUrlData($filterName); $brandSelected = $defSelected; if ($brandSelected) { if ($brandSelected == $this->getFilterSetting($settings, 'f_select_default_id')) { $filter['is_ids'] = true; } $ids = explode('|', $brandSelected); if (count($ids) <= 1) { $ids = explode(',', $brandSelected); } $brandSelected = $ids; } elseif ( $hiddenBrands && $includeBrandId ) { $brandSelected = $includeBrandId; $filter['is_ids'] = true; } $layout = $this->getFilterLayout($settings, $filterSettings); $inLineClass = $layout['class']; $logic = $this->getFilterSetting($settings, 'f_query_logic', 'or', false, array('or', 'and')); $notIds = ''; $notValues = ''; if ($hiddenBrands) { if (!$includeBrandId && $excludeIds) { $logic = 'not'; $notValues = '" data-not-ids="' . esc_attr($excludeIds); } } $htmlOpt = ''; if ($defSelected && !$hideEmptyActive) { $showedTerms = $allTerms; $showFilter = true; } if ( in_array($type, $frontendTypes) || $isMulti ) { self::$leer = true; $htmlOpt = $this->generateTaxonomyOptionsHtml( $productBrand, $brandSelected, $filter, $excludeIds, '', $layout, $includeBrandId, $showedTerms, $countsTerms ); if ( 'list' === $type || 'multi' === $type ) { $maxHeight = $this->getFilterSetting($settings, 'f_max_height', 0, true); if ($maxHeight > 0) { $this->setFilterCss('#' . self::$blockId . ' .wpfFilterVerScroll {max-height:' . $maxHeight . 'px;}'); } $htmlOpt = '<ul class="wpfFilterVerScroll' . $inLineClass . '">' . $htmlOpt . '</ul>'; } elseif ('dropdown' === $type) { $htmlOpt = '<select><option value="" data-slug="">' . esc_html__($this->getFilterSetting($settings, 'f_dropdown_first_option_text', 'Select all'), 'woo-product-filter') . '</option>' . $htmlOpt . '</select>'; } elseif ( 'mul_dropdown' === $type ) { $htmlOpt = $this->getMultiSelectHtml( $htmlOpt, $settings ); } } else { $htmlOpt = DispatcherWpf::applyFilters('getTaxonomyOptionsHtml', $htmlOpt, array( 'type' => $type, 'settings' => $filter, 'terms' => $productBrand, 'selected' => $brandSelected, 'showed' => $showedTerms, 'counts' => $countsTerms, 'excludes' => $excludeIds, 'includes' => $includeBrandId, 'display' => $layout, 'class' => $inLineClass )); } $noActive = $defSelected ? '' : 'wpfNotActive'; $noActive = $hiddenBrands ? 'wpfHidden' : $noActive; $preselected = $hiddenBrands ? ' wpfPreselected' : ''; $blockStyle = ( !$showFilter || ( !$showAllBrands && self::$isLeerFilter ) ? 'display:none;' : '' ) . $blockStyle; if (!empty($blockStyle)) { $this->setFilterCss('#' . self::$blockId . ' {' . $blockStyle . '}'); } $description = DispatcherWpf::applyFilters( 'productLoopStart', '', $settings ); $showCount = $this->getFilterSetting($settings, 'f_show_count', false) ? ' wpfShowCount' : ''; $hierarchical = $isHierarchical ? 'true' : 'false'; $html = '<div class="wpfFilterWrapper ' . $noActive . $showCount . $preselected . '"' . $this->setFitlerId() . $this->setCommonFitlerDataAttr($filter, $filterName, $type) . ' data-radio="' . ( 'list' === $type ? '1' : '0' ) . '" data-query-logic="' . $logic . $notValues . '" data-query-children="' . ( $isIncludeChildren ? '1' : '0' ) . '" data-show-hierarchical="' . $hierarchical . '" data-taxonomy="pwb-brand' . '" data-hide-active="' . ( $hideEmptyActive ? '1' : '0' ) . '" data-show-all="' . ( (int) $showAllBrands ) . '"' . $filter['blockAttributes'] . '>'; if ('' !== $description) { $html .= '<div class="data-brand-description" style="display:none;">' . $description . '</div>'; } $html .= $this->generateFilterHeaderHtml($filter, $filterSettings, $noActive); $html .= $this->generateDescriptionHtml($filter); if ( 'list' === $type && $this->getFilterSetting($settings, 'f_show_search_input', false) ) { $html .= '<div class="wpfSearchWrapper"><input class="wpfSearchFieldsFilter" type="text" placeholder="' . esc_html__($this->getFilterSetting($settings, 'f_search_label', $labels['search']), 'woo-product-filter') . '"></div>'; } $html .= '<div class="wpfCheckboxHier">'; $html .= $htmlOpt; $html .= '</div>';//end wpfCheckboxHier $html .= '</div>';//end wpfFilterContent $html .= '</div>';//end wpfFilterWrapper return $html; } public function generateTagsFilterHtml( $filter, $filterSettings, $blockStyle, $key = 0, $viewId = '' ) { $settings = $this->getFilterSetting($filter, 'settings', array()); $labels = FrameWpf::_()->getModule('woofilters')->getModel('woofilters')->getFilterLabels('Tags'); $hidden_tags = isset($filter['settings']['f_hidden_tags']) ? $filter['settings']['f_hidden_tags'] : false; $includeTagsId = !empty($filter['settings']['f_mlist[]']) ? explode(',', $filter['settings']['f_mlist[]']) : false; $excludeIds = !empty($filter['settings']['f_exclude_terms']) ? $filter['settings']['f_exclude_terms'] : false; $hideEmpty = $this->getFilterSetting($settings, 'f_hide_empty', false); $hideEmptyActive = $hideEmpty && $this->getFilterSetting($settings, 'f_hide_empty_active', false); $args = [ 'parent' => 0, 'hide_empty' => $hideEmpty, 'include' => $includeTagsId ]; $isCustomOrder = $includeTagsId && !empty($settings['f_order_custom']); $order = !$isCustomOrder && !empty($settings['f_sort_by']) ? $settings['f_sort_by'] : 'default'; $isDefaultOrder = ( 'default' === $order ); if ($isCustomOrder || !$isDefaultOrder) { $args = array_merge($args, [ 'orderby' => ( $isCustomOrder ? 'include' : 'name' ), 'order' => ( $isDefaultOrder ? 'asc' : $order ), 'sort_as_numbers' => ( $isDefaultOrder ? false : $this->getFilterSetting($settings, 'f_sort_as_numbers', false) ), ]); } $show_all_tags = isset($filter['settings']['f_show_all_tags']) ? $filter['settings']['f_show_all_tags'] : false; $taxonomy = 'product_tag'; $filterName = $this->getFilterSetting($filter, 'name', 'product_tag'); $filterName .= '_' . $key; list($showedTerms, $countsTerms, $showFilter, $allTerms) = $this->getShowedTerms($taxonomy, $show_all_tags, $filterName); $productTag = $this->getTaxonomyHierarchy($taxonomy, $args); if (!$productTag) { return ''; } $defSelected = $this->getFilterUrlData($filterName); $tagSelected = $defSelected; if ($tagSelected) { if ($tagSelected == $this->getFilterSetting($settings, 'f_select_default_id')) { $filter['is_ids'] = true; } $ids = explode('|', $tagSelected); if (count($ids) <= 1) { $ids = explode(',', $tagSelected); } $tagSelected = $ids; } elseif ( $hidden_tags && $includeTagsId ) { $tagSelected = $includeTagsId; $filter['is_ids'] = true; } $layout = $this->getFilterLayout($settings, $filterSettings); $inLineClass = $layout['class']; $frontendTypes = array('list', 'dropdown', 'mul_dropdown'); $type = $this->getFilterSetting($settings, 'f_frontend_type', 'list', null, DispatcherWpf::applyFilters('getFrontendFilterTypes', $frontendTypes, $filter['id'])); $logic = $this->getFilterSetting($settings, 'f_query_logic', 'or', false, array('or', 'and')); $notIds = ''; $notValues = ''; if ($hidden_tags) { $type = 'list'; if (!$includeTagsId && $excludeIds) { $logic = 'not'; $notValues = '" data-not-ids="' . esc_attr($excludeIds); } } $filter['settings']['f_frontend_type'] = $type; $htmlOpt = ''; if ($defSelected && !$hideEmptyActive) { $showedTerms = $allTerms; $showFilter = true; } if (in_array($type, $frontendTypes)) { self::$leer = true; $htmlOpt = $this->generateTaxonomyOptionsHtml( $productTag, $tagSelected, $filter, $excludeIds, '', $layout, false, $showedTerms, $countsTerms ); if ('list' === $type) { $maxHeight = $this->getFilterSetting($settings, 'f_max_height', 0, true); if ($maxHeight > 0) { $this->setFilterCss('#' . self::$blockId . ' .wpfFilterVerScroll {max-height:' . $maxHeight . 'px;}'); } $htmlOpt = '<ul class="wpfFilterVerScroll' . $inLineClass . '">' . $htmlOpt . '</ul>'; } elseif ('dropdown' === $type) { if (!empty($filter['settings']['f_dropdown_first_option_text'])) { $htmlOpt = '<option value="" data-slug="">' . esc_html__($filter['settings']['f_dropdown_first_option_text'], 'woo-product-filter') . '</option>' . $htmlOpt; } else { $htmlOpt = '<option value="" data-slug="">' . esc_html__('Select all', 'woo-product-filter') . '</option>' . $htmlOpt; } $htmlOpt = '<select>' . $htmlOpt . '</select>'; $logic = 'or'; } elseif ('mul_dropdown' === $type) { $htmlOpt = $this->getMultiSelectHtml( $htmlOpt, $settings ); } } else { $htmlOpt = DispatcherWpf::applyFilters('getTaxonomyOptionsHtml', $htmlOpt, array( 'type' => $type, 'settings' => $filter, 'terms' => $productTag, 'selected' => $tagSelected, 'showed' => $showedTerms, 'counts' => $countsTerms, 'excludes' => $excludeIds, 'includes' => false, 'display' => $layout, 'class' => $inLineClass, 'show_all' => $show_all_tags, 'view_id' => $viewId, )); } $noActive = $defSelected ? '' : 'wpfNotActive'; $noActive = $hidden_tags ? 'wpfHidden' : $noActive; $preselected = $hidden_tags ? ' wpfPreselected' : ''; $blockStyle = ( !$showFilter || ( !$show_all_tags && self::$isLeerFilter ) ? 'display:none;' : '' ) . $blockStyle; if (!empty($blockStyle)) { $this->setFilterCss('#' . self::$blockId . ' {' . $blockStyle . '}'); } $showCount = $filter['settings']['f_show_count'] ? ' wpfShowCount' : ''; $html = '<div class="wpfFilterWrapper ' . $noActive . $showCount . $preselected . '"' . $this->setFitlerId() . $this->setCommonFitlerDataAttr($filter, $filterName, $type) . ' data-query-logic="' . $logic . $notValues . '" data-taxonomy="product_tag' . '" data-hide-active="' . ( $hideEmptyActive ? '1' : '0' ) . '" data-show-all="' . ( (int) $show_all_tags ) . '"' . $filter['blockAttributes'] . '>'; $html .= $this->generateFilterHeaderHtml($filter, $filterSettings, $noActive); $html .= $this->generateDescriptionHtml($filter); if ( 'list' === $type && $this->getFilterSetting($settings, 'f_show_search_input', false) ) { $html .= '<div class="wpfSearchWrapper"><input class="wpfSearchFieldsFilter" type="text" placeholder="' . esc_html__($this->getFilterSetting($settings, 'f_search_label', $labels['search']), 'woo-product-filter') . '"></div>'; } $html .= '<div class="wpfCheckboxHier">'; $html .= $htmlOpt; $html .= '</div>';//end wpfCheckboxHier $html .= '</div>';//end wpfFilterContent $html .= '</div>';//end wpfFilterWrapper return $html; } public function generateAuthorFilterHtml( $filter, $filterSettings, $blockStyle, $key = 1, $viewId = '' ) { $settings = $this->getFilterSetting($filter, 'settings', array()); $labels = FrameWpf::_()->getModule('woofilters')->getModel('woofilters')->getFilterLabels('Author'); $roleNames = !empty($filter['settings']['f_mlist[]']) ? explode(',', $filter['settings']['f_mlist[]']) : false; $filterName = 'pr_author'; //show all roles if user not make choise if (!$roleNames) { if ( ! function_exists( 'get_editable_roles' ) ) { require_once ABSPATH . 'wp-admin/includes/user.php'; } $rolesMain = get_editable_roles(); $roleNames = array(); foreach ($rolesMain as $key => $role) { $roleNames[] = $key; } } $userExistList = array(); foreach (self::$filterExistsUsers as $userData) { $userExistList[] = $userData['ID']; } $args = array( 'role__in' => $roleNames, 'fields' => array('ID', 'display_name', 'user_nicename') ); $usersMain = get_users( $args ); $users = array(); $userSelectedSlugs = array(); $userShowedIds = array(); foreach ($usersMain as $key => $user) { $u = new stdClass(); $u->term_id = $user->ID; $u->name = $user->display_name; $u->slug = $user->user_nicename; if ( $userExistList && in_array( $user->ID, $userExistList ) ) { $userShowedIds[] = $user->ID; $storeName = get_user_meta( $user->ID, 'store_name', true ); if ( '' !== $storeName ) { $u->name = $storeName; } } $users[] = $u; if ( strpos( ReqWpf::getVar( 'pr_author', 'all', '' ), $user->user_nicename ) !== false ) { $userSelectedSlugs[] = $user->user_nicename; $filter['is_slugs'] = true; } } $layout = $this->getFilterLayout($settings, $filterSettings); if ($layout['is_ver']) { $this->setFilterCss('#' . self::$blockId . ' {display: inline-block; min-width: auto;}'); } self::$leer = true; $htmlOpt = $this->generateTaxonomyOptionsHtml( $users, $userSelectedSlugs, $filter, false, '', $layout, false, $userShowedIds ); $type = $filter['settings']['f_frontend_type']; if ('list' === $type) { $maxHeight = $this->getFilterSetting($settings, 'f_max_height', 0, true); if ($maxHeight > 0) { $this->setFilterCss('#' . self::$blockId . ' .wpfFilterVerScroll {max-height:' . $maxHeight . 'px;}'); } $wrapperStart = '<ul class="wpfFilterVerScroll' . $layout['class'] . '">'; $wrapperEnd = '</ul>'; } elseif ('dropdown' === $type) { $wrapperStart = '<select>'; if (!empty($filter['settings']['f_dropdown_first_option_text'])) { $htmlOpt = '<option value="" data-slug="">' . esc_html__($filter['settings']['f_dropdown_first_option_text'], 'woo-product-filter') . '</option>' . $htmlOpt; } else { $htmlOpt = '<option value="" data-slug="">' . esc_html__('Select all', 'woo-product-filter') . '</option>' . $htmlOpt; } $wrapperEnd = '</select>'; } elseif ('mul_dropdown' === $type) { $wrapperStart = ''; $wrapperEnd = ''; $htmlOpt = $this->getMultiSelectHtml( $htmlOpt, $settings ); } $noActive = ReqWpf::getVar('pr_author') ? '' : 'wpfNotActive'; $html = '<div class="wpfFilterWrapper ' . $noActive . '"' . $this->setFitlerId() . $this->setCommonFitlerDataAttr($filter, $filterName, $type) . $filter['blockAttributes'] . '>'; $html .= $this->generateFilterHeaderHtml($filter, $filterSettings, $noActive); $html .= $this->generateDescriptionHtml($filter); if ( 'list' === $type && $this->getFilterSetting($settings, 'f_show_search_input', false) ) { $html .= '<div class="wpfSearchWrapper">' . '<input class="wpfSearchFieldsFilter" type="text" placeholder="' . esc_html__($this->getFilterSetting($settings, 'f_search_label', $labels['search']), 'woo-product-filter') . '">' . '</div>'; } $html .= '<div class="wpfCheckboxHier">'; $html .= $wrapperStart; $html .= $htmlOpt; $html .= $wrapperEnd; $html .= '</div>';//end wpfCheckboxHier $html .= '</div>';//end wpfFilterContent $html .= '</div>';//end wpfFilterWrapper return $html; } public function generateFeaturedFilterHtml( $filter, $filterSettings, $blockStyle, $key = 1, $viewId = '' ) { $filterName = 'pr_featured'; $settings = $this->getFilterSetting($filter, 'settings', array()); $layout = $this->getFilterLayout($settings, $filterSettings); $inLineClass = $layout['class']; if ($layout['is_ver']) { $this->setFilterCss('#' . self::$blockId . ' {display: inline-block; min-width: auto;}'); } $u = new stdClass(); $u->term_id = '1'; $u->name = __($this->getFilterSetting($filter['settings'], 'f_custom_title', 'Featured'), 'woo-product-filter'); $u->slug = '1'; $feature[] = $u; $featureSelected = array(ReqWpf::getVar($filterName)); $frontendTypes = array('list'); $type = $this->getFilterSetting($filter['settings'], 'f_frontend_type', 'list', null, DispatcherWpf::applyFilters('getFrontendFilterTypes', $frontendTypes, $filter['id'])); $filter['settings']['f_frontend_type'] = $type; $htmlOpt = ''; $selectDefaultId = DispatcherWpf::applyFilters('getDefaultId', $filter['settings']); if ( is_numeric($selectDefaultId) ) { $featureSelected[] = $selectDefaultId; } if (in_array($type, $frontendTypes)) { self::$leer = true; $htmlOpt = $this->generateTaxonomyOptionsHtml( $feature, $featureSelected, $filter, false, '', $layout ); $htmlOpt = '<ul class="wpfFilterVerScroll' . $inLineClass . '">' . $htmlOpt . '</ul>'; } else { $htmlOpt = DispatcherWpf::applyFilters('getTaxonomyOptionsHtml', $htmlOpt, array( 'type' => $type, 'settings' => $filter, 'terms' => $feature, 'selected' => $featureSelected, 'display' => $layout, 'class' => $inLineClass )); } $noActive = ReqWpf::getVar('pr_featured') ? '' : 'wpfNotActive'; $html = '<div class="wpfFilterWrapper ' . $noActive . '"' . $this->setFitlerId() . $this->setCommonFitlerDataAttr($filter, $filterName, $filter['settings']['f_frontend_type']) . $filter['blockAttributes'] . '>'; $html .= $this->generateFilterHeaderHtml($filter, $filterSettings, $noActive); $html .= $this->generateDescriptionHtml($filter); $html .= '<div class="wpfCheckboxHier">'; $html .= $htmlOpt; $html .= '</div>';//end wpfCheckboxHier $html .= '</div>';//end wpfFilterContent $html .= '</div>';//end wpfFilterWrapper return $html; } public function generateOnSaleFilterHtml( $filter, $filterSettings, $blockStyle, $key = 1, $viewId = '' ) { $filterName = 'pr_onsale'; $settings = $this->getFilterSetting($filter, 'settings', array()); $defaultOnsale = FrameWpf::_()->isPro() ? $this->getFilterSetting($settings, 'f_default_onsale', false) : false; $hiddenOnsale = $defaultOnsale && $this->getFilterSetting($settings, 'f_hidden_onsale', false); $layout = $this->getFilterLayout($settings, $filterSettings); $inLineClass = $layout['class']; if ($layout['is_ver']) { $this->setFilterCss('#' . self::$blockId . ' {display: inline-block; min-width: auto;}'); } $labels = FrameWpf::_()->getModule('woofilters')->getModel('woofilters')->getFilterLabels('OnSale'); $label = __($this->getFilterSetting($settings, 'f_checkbox_label', $labels['onsale']), 'woo-product-filter'); $u = new stdClass(); $u->term_id = '1'; $u->name = $label; $u->slug = '1'; $onSale[] = $u; $defSelected = $this->getFilterUrlData($filterName); $onSaleSelected = $hiddenOnsale ? array(1) : array($defSelected); $frontendTypes = array('list'); $type = $this->getFilterSetting($filter['settings'], 'f_frontend_type', 'list', null, DispatcherWpf::applyFilters('getFrontendFilterTypes', $frontendTypes, $filter['id'])); $filter['settings']['f_frontend_type'] = $type; $htmlOpt = ''; if (in_array($type, $frontendTypes)) { self::$leer = true; $htmlOpt = $this->generateTaxonomyOptionsHtml( $onSale, $onSaleSelected, $filter, false, '', $layout ); $htmlOpt = '<ul class="wpfFilterVerScroll' . $inLineClass . '">' . $htmlOpt . '</ul>'; } else { $htmlOpt = DispatcherWpf::applyFilters('getTaxonomyOptionsHtml', $htmlOpt, array( 'type' => $type, 'settings' => $filter, 'terms' => $onSale, 'selected' => $onSaleSelected, 'display' => $layout, 'class' => $inLineClass )); } $noActive = $defSelected ? '' : 'wpfNotActive'; if ($hiddenOnsale) { $noActive = 'wpfHidden wpfPreselected'; } $html = '<div class="wpfFilterWrapper ' . $noActive . '"' . $this->setFitlerId() . $this->setCommonFitlerDataAttr($filter, $filterName, $filter['settings']['f_frontend_type']) . '>'; $html .= $this->generateFilterHeaderHtml($filter, $filterSettings, $noActive); $html .= $this->generateDescriptionHtml($filter); $html .= '<div class="wpfCheckboxHier">'; $html .= $htmlOpt; $html .= '</div>';//end wpfCheckboxHier $html .= '</div>';//end wpfFilterContent $html .= '</div>';//end wpfFilterWrapper return $html; } public function generateInStockFilterHtml( $filter, $filterSettings, $blockStyle, $key = 1, $viewId = '' ) { $optionsAll = FrameWpf::_()->getModule('woofilters')->getModel('woofilters')->getFilterLabels('InStock'); $settings = $this->getFilterSetting($filter, 'settings', array()); $options = $this->getFilterSetting($settings, 'f_options[]', ''); $options = explode(',', $options); $defSelected = $this->getFilterUrlData('pr_stock'); $stockSelected = $defSelected; if ($stockSelected) { $stockSelected = explode('|', $stockSelected); } $inStock = array(); $changeNames = ( $this->getFilterSetting($settings, 'f_status_names', '') == 'on' ); $names = array('instock' => 'in', 'outofstock' => 'out', 'onbackorder' => 'on'); $i = 0; foreach ($options as $key) { if (isset($optionsAll[$key])) { $i++; $u = new stdClass(); $u->term_id = $i; $u->name = $changeNames ? $this->getFilterSetting($settings, 'f_stock_statuses[' . $names[$key] . ']', $optionsAll[$key]) : $optionsAll[$key]; $u->name = __($u->name, 'woo-product-filter'); $u->slug = $key; $inStock[] = $u; } } $frontendTypes = array('dropdown', 'list'); $type = $this->getFilterSetting($filter['settings'], 'f_frontend_type', 'dropdown', null, DispatcherWpf::applyFilters('getFrontendFilterTypes', $frontendTypes, $filter['id'])); $filter['settings']['f_frontend_type'] = $type; $filter['is_slugs'] = true; $htmlOpt = ''; if (in_array($type, $frontendTypes)) { self::$leer = true; $htmlOpt = $this->generateTaxonomyOptionsHtml( $inStock, $stockSelected, $filter, false, '', false ); if ('list' === $type) { $htmlOpt = '<ul class="wpfFilterVerScroll">' . $htmlOpt . '</ul>'; } elseif ('dropdown' === $type) { $htmlOpt = '<option value="" data-slug="">' . esc_html__($this->getFilterSetting($settings, 'f_dropdown_first_option_text', 'Select all'), 'woo-product-filter') . '</option>' . $htmlOpt; $htmlOpt = '<select>' . $htmlOpt . '</select>'; $logic = 'or'; } } else { $htmlOpt = DispatcherWpf::applyFilters('getTaxonomyOptionsHtml', $htmlOpt, array( 'type' => $type, 'settings' => $filter, 'terms' => $inStock, 'selected' => $stockSelected )); } $noActive = $defSelected ? '' : 'wpfNotActive'; $html = '<div class="wpfFilterWrapper ' . $noActive . '"' . $this->setFitlerId() . $this->setCommonFitlerDataAttr($filter, 'pr_stock', $filter['settings']['f_frontend_type']) . $filter['blockAttributes'] . '>'; $html .= $this->generateFilterHeaderHtml($filter, $filterSettings, $noActive); $html .= $this->generateDescriptionHtml($filter); $html .= $htmlOpt; $html .= '</div>';//end wpfFilterContent $html .= '</div>'; //end wpfFilterWrapper return $html; } public function generateRatingFilterHtml( $filter, $filterSettings, $blockStyle, $key = 1, $viewId = '' ) { $filterName = 'pr_rating'; $ratingSelected = ReqWpf::getVar($filterName); $settings = $this->getFilterSetting($filter, 'settings', array()); $type = $this->getFilterSetting($settings, 'f_frontend_type', 'list', null, array('list', 'dropdown', 'mul_dropdown')); $filter['settings']['f_frontend_type'] = $type; $addText = __($this->getFilterSetting($settings, 'f_add_text', 'and up'), 'woo-product-filter'); $addText5 = __($this->getFilterSetting($settings, 'f_add_text5', '5 only'), 'woo-product-filter'); $useExactValues = $this->getFilterSetting($settings, 'f_use_exact_values', false); $wrapperStart = '<ul class="wpfFilterVerScroll">'; $wrapperEnd = '</ul>'; if (!$useExactValues) { $ratingItems = array( array('1', $addText5, '5-5'), array('2', '4 ' . $addText, '4-5'), array('3', '3 ' . $addText, '3-5'), array('4', '2 ' . $addText, '2-5'), array('5', '1 ' . $addText, '1-5'), ); } else { $ratingItems = array( array('1', '5', '5'), array('2', '4', '4'), array('3', '3', '3'), array('4', '2', '2'), array('5', '1', '1'), ); } $rating = array(); foreach ($ratingItems as $item) { $u = new stdClass(); $u->term_id = $item[2]; $u->name = $item[1]; $u->slug = $item[2]; $rating[] = $u; } $layout = $this->getFilterLayout($settings, $filterSettings); if ( !is_array($ratingSelected) ) { $ratingSelected = array($ratingSelected); } self::$leer = true; $htmlOpt = $this->generateTaxonomyOptionsHtml( $rating, $ratingSelected, $filter, false, '', $layout ); if ('list' === $type) { $wrapperStart = '<ul class="wpfFilterVerScroll' . $layout['class'] . '">'; $wrapperEnd = '</ul>'; } elseif ('dropdown' === $type) { $wrapperStart = '<select>'; $text = $this->getFilterSetting($settings, 'f_dropdown_first_option_text'); if (!empty($text)) { $htmlOpt = '<option value="" data-slug="">' . esc_html__($text, 'woo-product-filter') . '</option>' . $htmlOpt; } else { $htmlOpt = '<option value="" data-slug="">' . esc_html__('Select all', 'woo-product-filter') . '</option>' . $htmlOpt; } $wrapperEnd = '</select>'; } elseif ('mul_dropdown' === $type) { $wrapperStart = '<select multiple>'; $wrapperEnd = '</select>'; } $noActive = ReqWpf::getVar($filterName) ? '' : 'wpfNotActive'; $html = '<div class="wpfFilterWrapper ' . $noActive . '"' . $this->setFitlerId() . $this->setCommonFitlerDataAttr($filter, $filterName, $type) . $filter['blockAttributes'] . '>'; $html .= $this->generateFilterHeaderHtml($filter, $filterSettings, $noActive); $html .= $this->generateDescriptionHtml($filter); $html .= '<div class="wpfCheckboxHier">'; $html .= $wrapperStart; $html .= $htmlOpt; $html .= $wrapperEnd; $html .= '</div>';//end wpfCheckboxHier $html .= '</div>';//end wpfFilterContent $html .= '</div>';//end wpfFilterWrapper return $html; } public function generateAttributeFilterHtml( $filter, $filterSettings, $blockStyle, $key = 1, $viewId = '' ) { $settings = $this->getFilterSetting($filter, 'settings', array()); $labels = FrameWpf::_()->getModule('woofilters')->getModel('woofilters')->getFilterLabels('Attribute'); $frontendTypes = array('list', 'radio', 'dropdown', 'mul_dropdown'); $hidden_atts = $this->getFilterSetting($settings, 'f_hidden_attributes', false); $type = $hidden_atts ? 'list' : $this->getFilterSetting($settings, 'f_frontend_type', 'list', null, DispatcherWpf::applyFilters('getFrontendFilterTypes', $frontendTypes, $filter['id'])); $filter['settings']['f_frontend_type'] = $type; $includeAttsId = ( !empty($settings['f_mlist[]']) ) ? explode(',', $settings['f_mlist[]']) : false; $attrId = $this->getFilterSetting($settings, 'f_list', 0, true); $excludeIds = $this->getFilterSetting($settings, 'f_exclude_terms', false); $hideEmpty = $this->getFilterSetting($settings, 'f_hide_empty', false); $hideEmptyActive = $hideEmpty && $this->getFilterSetting($settings, 'f_hide_empty_active', false); $hideBySingle = $hideEmpty && $this->getFilterSetting($settings, 'f_hide_by_single', false); $args = [ 'parent' => 0, 'hide_empty' => $hideEmpty, 'include' => $includeAttsId ]; $isCustomOrder = $includeAttsId && !empty($settings['f_order_custom']); $order = !$isCustomOrder && !empty($settings['f_sort_by']) ? $settings['f_sort_by'] : 'default'; $isDefaultOrder = ( 'default' === $order ); if ($isCustomOrder || !$isDefaultOrder) { $args = array_merge($args, [ 'orderby' => ( $isCustomOrder ? 'include' : 'name' ), 'order' => ( $isDefaultOrder ? 'asc' : $order ), 'sort_as_numbers' => ( $isDefaultOrder ? false : $this->getFilterSetting($settings, 'f_sort_as_numbers', false) ), ]); } $needIndex = FrameWpf::_()->getModule( 'woofilters' )->getView()->needIndex; $index = ( in_array( $filter['name'], $needIndex ) ) ? "_{$key}" : ''; $isCustom = !empty($filter['custom_taxonomy']); if ($isCustom) { $customTaxonomy = $filter['custom_taxonomy']; $attrName = $customTaxonomy->attribute_name; $attrSlug = $customTaxonomy->attribute_slug; $attrLabel = strtolower($customTaxonomy->attribute_label); $filterNameSlug = $attrSlug; $filterName = "{$customTaxonomy->filter_name}{$index}"; } else { $attrName = wc_attribute_taxonomy_name_by_id((int) $attrId); $attrLabel = strtolower(wc_attribute_label($attrName)); $filterNameSlug = str_replace('pa_', '', $attrName); $filterName = "wpf_filter_{$filterNameSlug}{$index}"; } $attrLabel = strip_tags($attrLabel); $logic = FrameWpf::_()->getModule('woofilters')->getAttrFilterLogic(); $logicSlug = $this->getFilterSetting($settings, 'f_query_logic', 'or', false, array_keys($logic['loop'])); $notIds = ''; $notValues = ''; if ($hidden_atts) { if (!$includeAttsId && $excludeIds) { $logicSlug = 'not'; $notValues = '" data-not-ids="' . esc_attr($excludeIds); } } $show_all_atts = isset($filter['settings']['f_show_all_attributes']) ? $filter['settings']['f_show_all_attributes'] : false; // add additional slug for filter name if logic is out of standard woocmmerce filter if ('not_in' == $logicSlug) { $filterName = 'pr_' . $filterName; $show_all_atts = true; } $fList = $this->getFilterSetting( $settings, 'f_list' ); list( $showedTerms, $countsTerms, $showFilter, $allTerms ) = $this->getShowedTerms( $attrName, $show_all_atts, $filterName ); //doing the sorting through the hook while some themes/plugins impose their own if ($isCustomOrder) { $args['wpf_orderby'] = implode(',', $includeAttsId); add_filter('terms_clauses', array($this, 'wpfAddTermsClauses'), 99, 3); } if ($isCustom) { $custArgs = array( 'wpf_fbv' => $this->getFilterSetting($filterSettings['settings'], 'filtering_by_variations'), 'all_attrs' => $this->getFilterSetting($settings, 'f_show_all_attributes', false) ); } $productAttr = $isCustom ? DispatcherWpf::applyFilters('getCustomTerms', array(), $attrSlug, array_merge($args, $custArgs)) : $this->getTaxonomyHierarchy($attrName, $args); remove_filter('terms_clauses', array($this, 'wpfAddTermsClauses'), 99, 3); if (!$productAttr) { return ''; } $defSelected = $this->getFilterUrlData($filterName); $attrSelected = $defSelected; if ($attrSelected) { if ($attrSelected == $this->getFilterSetting($settings, 'f_select_default_id')) { $attrSelected = explode( '|', $attrSelected ); $filter['is_ids'] = true; } else { $delimetrList = array_values( $logic['delimetr'] ); foreach ( $delimetrList as $delimetr ) { $slugs = explode( $delimetr, $attrSelected ); if ( count( $slugs ) > 1 ) { break; } } } } elseif ( $hidden_atts && $includeAttsId ) { $attrSelected = $includeAttsId; $filter['is_ids'] = true; } if ( ! empty( $slugs ) ) { $changeToId = false; $module = FrameWpf::_()->getModule( 'woofilterpro' ); if ( isset( $module->acf_prefix ) && 0 === strpos( $filterName, $module->acf_prefix ) ) { $key = str_replace( $module->acf_prefix, '', $filterName ); $keyId = FrameWpf::_()->getModule('woofilters')->getMetaKeyId( $key ); $changeToId = true; } foreach ( $slugs as &$value ) { $value = ( $changeToId && ! is_numeric( $value ) ) ? FrameWpf::_()->getModule( 'meta' )->getModel( 'meta_values' )->getMetaValueId( $keyId, $value ) : strtolower( urlencode( $value ) ); } $attrSelected = $slugs; } $layout = $this->getFilterLayout($settings, $filterSettings); $inLineClass = $layout['class']; $htmlOpt = ''; if ($defSelected && !$hideEmptyActive) { $showedTerms = ( !empty($allTerms) ) ? $allTerms : false; $showFilter = true; } if (in_array($type, $frontendTypes)) { self::$leer = true; $htmlOpt = $this->generateTaxonomyOptionsHtml( $productAttr, $attrSelected, $filter, $excludeIds, '', $layout, false, $showedTerms, $countsTerms ); if ('list' == $type || 'radio' == $type) { $maxHeight = $this->getFilterSetting($settings, 'f_max_height', 0, true); if ($maxHeight > 0) { $this->setFilterCss('#' . self::$blockId . ' .wpfFilterVerScroll {max-height:' . $maxHeight . 'px;}'); } $htmlOpt = '<ul class="wpfFilterVerScroll' . $inLineClass . '">' . $htmlOpt . '</ul>'; } elseif ('dropdown' == $type) { $htmlOpt = '<select><option value="" data-slug="" data-file="2299">' . esc_html__($this->getFilterSetting($settings, 'f_dropdown_first_option_text', 'Select all'), 'woo-product-filter') . '</option>' . $htmlOpt . '</select>'; } elseif ('mul_dropdown' == $type) { $htmlOpt = $this->getMultiSelectHtml( $htmlOpt, $settings ); } } else { $htmlOpt = DispatcherWpf::applyFilters('getTaxonomyOptionsHtml', $htmlOpt, array( 'type' => $type, 'settings' => $filter, 'terms' => $productAttr, 'selected' => $attrSelected, 'showed' => $showedTerms, 'counts' => $countsTerms, 'excludes' => $excludeIds, 'includes' => false, 'display' => $layout, 'class' => $inLineClass )); } $blockStyle = ( !$showFilter || ( !$show_all_atts && self::$isLeerFilter ) ? 'display:none;' : '' ) . $blockStyle; if (!empty($blockStyle)) { $this->setFilterCss('#' . self::$blockId . ' {' . $blockStyle . '}'); } $noActive = $defSelected ? '' : 'wpfNotActive'; $noActive = $hidden_atts ? 'wpfHidden' : $noActive; $showCount = $filter['settings']['f_show_count'] ? ' wpfShowCount' : ''; $preselected = $hidden_atts ? ' wpfPreselected' : ''; $html = '<div class="wpfFilterWrapper ' . $noActive . $showCount . $preselected . '"' . $this->setFitlerId() . $this->setCommonFitlerDataAttr($filter, $filterName, $type, esc_attr($filterNameSlug)) . ' data-query-logic="' . $logicSlug . $notValues . '" data-radio="' . ( 'radio' === $type ? '1' : '0' ) . '" data-taxonomy="' . $attrName . '" data-label="' . ( '' !== $attrLabel ? $attrLabel : $filterNameSlug ) . '" data-hide-active="' . ( $hideEmptyActive ? '1' : '0' ) . '" data-show-all="' . ( (int) $show_all_atts ) . '" data-hide-single="' . ( (int) $hideBySingle ) . '"' . $filter['blockAttributes'] . '>'; $html .= $this->generateFilterHeaderHtml($filter, $filterSettings, $noActive); $html .= $this->generateDescriptionHtml($filter); $html .= $this->generateSearchFieldList('<div class="wpfCheckboxHier">' . $htmlOpt . '</div>', $settings, $labels); $html .= '</div>';//end wpfFilterContent $html .= '</div>';//end wpfFilterWrapper return $html; } public function generateSearchFieldList( $html, $settings, $labels ) { $type = $this->getFilterSetting($settings, 'f_frontend_type', 'list'); if ( ( 'list' != $type && 'radio' != $type ) || !$this->getFilterSetting($settings, 'f_show_search_input', false ) ) { return $html; } $isPro = FrameWpf::_()->isPro(); $search = '<div class="wpfSearchWrapper"><input class="wpfSearchFieldsFilter passiveFilter" type="text" placeholder="' . esc_html__($this->getFilterSetting($settings, 'f_search_label', $labels['search']), 'woo-product-filter') . '">'; if ($isPro && $this->getFilterSetting($settings, 'f_show_search_button', false)) { $search .= '<button></button>'; } $search .= '</div>'; if ($isPro && $this->getFilterSetting($settings, 'f_search_position', 'before') == 'after') { $html .= $search; } else { $html = $search . $html; } return $html; } /** * Get curent taxonomy terms (as exeption right now we use it also with acf meta) * * @param string $taxonomy * @param bool $showAll * * @return array */ public function getShowedTerms( $taxonomy, $showAll, $filterName = '' ) { $showFilter = true; $showedTerms = false; $countsTerms = false; $allTerms = false; $terms = self::$filterExistsTerms; $withoutFiltering = self::$filterExistsTermsWithotFiltering; if (is_array($terms)) { $countsTerms = array(); if (isset($terms[$taxonomy])) { if (!$showAll) { $showedTerms = array_keys($terms[$taxonomy]); } $countsTerms = $terms[$taxonomy]; } elseif (!$showAll) { $showedTerms = array(); } if (!$showAll && empty($showedTerms)) { $showFilter = false; } if (!self::$currentFilterRecount && isset($withoutFiltering[$taxonomy])) { $countsTerms = $withoutFiltering[$taxonomy]; } } if (!$showAll) { $allTerms = empty($withoutFiltering[$taxonomy]) ? array() : array_keys($withoutFiltering[$taxonomy]); } return array($showedTerms, $countsTerms, $showFilter, $allTerms); } public function wpfAddTermsClauses( $clauses, $taxonomies, $args ) { if (isset($args['wpf_orderby'])) { $clauses['orderby'] = ' ORDER BY FIELD( t.term_id, ' . $args['wpf_orderby'] . ')'; } return $clauses; } public function wpfGetTermsOrderby( $orderby, $args ) { return isset($args['wpf_orderby']) ? 'FIELD( t.term_id, ' . $args['wpf_orderby'] . ')' : $orderby; } /** * Recursively get taxonomy and its children * * @param string $taxonomy * @param int $parent - parent term id * @return array */ public function getTaxonomyHierarchy( $taxonomy, $argsIn, $parent = true ) { // only 1 taxonomy $taxonomy = is_array( $taxonomy ) ? array_shift( $taxonomy ) : $taxonomy; // get all direct decendants of the $parent $args = array( 'taxonomy' => $taxonomy, 'hide_empty' => $argsIn['hide_empty'], ); if (isset($argsIn['order'])) { $args['orderby'] = !empty($argsIn['orderby']) ? $argsIn['orderby'] : 'name'; $args['order'] = $argsIn['order']; } if (!empty($argsIn['include'])) { $args['include'] = $argsIn['include']; } if ( !empty($argsIn['parent']) && 0 !== $argsIn['parent'] ) { $args['parent'] = $argsIn['parent']; } else { $args['parent'] = 0; } if ('' === $taxonomy) { return false; } if ( 'product_cat' === $taxonomy && $parent ) { $args['parent'] = 0; } if (!empty($argsIn['include'])) { $args['include'] = $argsIn['include']; $args['parent'] = ''; $argsIn['only_parent'] = true; if (!empty($argsIn['wpf_orderby'])) { $args['wpf_orderby'] = $argsIn['wpf_orderby']; } } $terms = get_terms( $args ); // prepare a new array. these are the children of $parent // we'll ultimately copy all the $terms into this new array, but only after they // find their own children if (isset($argsIn['sort_as_numbers']) && $argsIn['sort_as_numbers']) { $terms = DispatcherWpf::applyFilters('sortAsNumbers', $terms, $args['order']); } $children = array(); // go through all the direct decendants of $parent, and gather their children if (!is_wp_error($terms)) { foreach ( $terms as $term ) { if (empty($argsIn['only_parent'])) { if (!empty($term->term_id)) { $args = array( 'hide_empty' => $argsIn['hide_empty'], 'parent' => $term->term_id, ); if (isset($argsIn['order'])) { $args['order'] = $argsIn['order']; $args['orderby'] = !empty($argsIn['orderby']) ? $argsIn['orderby'] : 'name'; } // recurse to get the direct decendants of "this" term $term->children = $this->getTaxonomyHierarchy( $taxonomy, $args, false ); } } // add the term to our new array $children[ $term->term_id ] = $term; } } // send the results back to the caller return $children; } public function wpfGetFilteredPriceFromProductList( $settings, $listTable, $convert = true, $dec = 0, $tax = '' ) { global $wpdb; list( $tax, $taxSql ) = DispatcherWpf::applyFilters( 'priceTax', array( '', '' ), 'add', $settings ); $module = FrameWpf::_()->getModule('woofilters'); $metas = apply_filters( 'woocommerce_price_filter_meta_keys', array( '_price' )); $metaIds = array(); $wpfMeta = true; foreach ($metas as $key) { $id = $module->getMetaKeyId($key); if ($id) { $metaIds[] = $id; } else { $wpfMeta = false; break; } } if ($wpfMeta) { if (empty($dec)) { $sql = "SELECT min( FLOOR( val_dec{$taxSql} ) ) as wpfMinPrice, max( CEILING( val_dec{$taxSql} ) ) as wpfMaxPrice "; } else { $sql = "SELECT min( ROUND( val_dec{$taxSql}, {$dec} ) ) as wpfMinPrice, max( ROUND( val_dec{$taxSql}, {$dec} ) ) as wpfMaxPrice"; } $query = $sql . ' FROM ' . $listTable . ' AS wpf_temp ' . ' INNER JOIN @__meta_data pm ON (pm.product_id=wpf_temp.ID) WHERE key_id IN (' . implode( ',', $metaIds ) . ')'; } else { if (empty($dec)) { $sql = "SELECT min( FLOOR( meta_value{$taxSql} ) ) as wpfMinPrice, max( CEILING( meta_value{$taxSql} ) ) as wpfMaxPrice "; } else { $sql = "SELECT min( ROUND( meta_value{$taxSql}, {$dec} ) ) as wpfMinPrice, max( ROUND( meta_value{$taxSql}, {$dec} ) ) as wpfMaxPrice"; } $query = $sql . ' FROM ' . $listTable . ' AS wpf_temp ' . ' INNER JOIN ' . $wpdb->postmeta . ' pm ON (pm.post_id=wpf_temp.ID) WHERE meta_key IN ("' . implode( "','", array_map( 'esc_sql', $metas ) ) . '")'; } $price = DbWpf::get($query, 'row', OBJECT); if ( $price && $convert ) { $price->wpfMaxPrice = $module->getCurrencyPrice( (float) $price->wpfMaxPrice, $dec ); $price->wpfMinPrice = $module->getCurrencyPrice( (float) $price->wpfMinPrice, $dec ); } if ( '' !== $tax ) { $price->tax = $tax; } return $price; } public function wpfGetFilteredPrice( $convert = true, $args = null, $dec = 0 ) { return self::$filterExistsPrices; } protected function generateTaxonomyOptionsHtmlFromPro( $filterItemList, $selectedElem, $filter = false, $excludeIds = false, $pre = '', $layout = 0, $includeIds = false, $showedTerms = false, $countsTerms = false ) { self::$leer = true; return $this->generateTaxonomyOptionsHtml($filterItemList, $selectedElem, $filter, $excludeIds, $pre, $layout, $includeIds, $showedTerms, $countsTerms); } private function generateTaxonomyOptionsHtml( $filterItemList, $selectedElem, $filter = false, $excludeIds = false, $pre = '', $layout = 0, $includeIds = false, $showedTerms = false, $countsTerms = false, $itemLevel = 0, $currentCategoryId = 0 ) { $html = ''; $settings = $this->getCurrentSettings(); $options = FrameWpf::_()->getModule( 'options' )->getModel( 'options' )->getAll(); if ( $excludeIds && !is_array($excludeIds) ) { $excludeIds = explode(',', $excludeIds); } if ( $includeIds && !is_array($includeIds) ) { $includeIds = explode(',', $includeIds); } $showCount = $this->getFilterSetting($filter['settings'], 'f_show_count'); $showImage = FrameWpf::_()->isPro() && $this->getFilterSetting($filter['settings'], 'f_show_images', false); $allProductsFiltering = $this->getFilterSetting($settings['settings'], 'all_products_filtering', false); if ( $allProductsFiltering && ( !empty($filter['custom_taxonomy'] ) || !empty($filter['custom_meta']) ) ) { $allProductsFiltering = false; } if ($showImage) { $imgSize = array($this->getFilterSetting($filter['settings'], 'f_images_width', 20), $this->getFilterSetting($filter['settings'], 'f_images_height', 20)); } $type = $this->getFilterSetting($filter['settings'], 'f_frontend_type', 'list'); $isMulti = ( 'multi' === $type ); if (FrameWpf::_()->isPro()) { if ( method_exists(FrameWpf::_()->getModule('woofilterpro'), 'getCollapsibleFiltreOptions') ) { $collapsibleList = FrameWpf::_()->getModule('woofilterpro')->getCollapsibleFiltreOptions($filter['id']); } else { $collapsibleList = array('multi'); } if ( in_array($type, $collapsibleList) ) { $isCollapsible = $this->getFilterSetting($filter['settings'], 'f_multi_collapsible', false); } } $isHierarchical = $this->getFilterSetting($filter['settings'], 'f_show_hierarchical', false); $hideParent = $isHierarchical && $this->getFilterSetting($filter['settings'], 'f_hide_parent', false); $hideAllParent = $isHierarchical && $this->getFilterSetting($filter['settings'], 'f_hide_all_parent', false); $showCustomTags = $this->getFilterSetting($filter['settings'], 'f_custom_tags', false); $titleTag = $this->getFilterSetting($filter['settings'], 'f_custom_tags_settings[title_1]', 0); $menuMode = ( 'mul_dropdown' == $type || 'multi' == $type ? false : $this->getFilterSetting($filter['settings'], 'f_menu_mode', false) ); if ($pre) { $preCount = count( explode(';', $pre) ); if ( 9 <= $preCount ) { $preCount = 4; } elseif ( 6 <= $preCount ) { $preCount = 3; } else { $preCount = 2; } $titleTag = $this->getFilterSetting($filter['settings'], 'f_custom_tags_settings[title_' . $preCount . ']', 0); } $titleTag = $titleTag && $showCustomTags ? FrameWpf::_()->getModule('woofilters')->getFilterTagsList()[$titleTag] : 'div'; if ( is_array($layout) && 'dropdown' != $type && 'mul_dropdown' != $type ) { if ($layout['is_ver']) { if ($layout['cnt'] > 1) { $width = number_format(100 / $layout['cnt'], 4, '.', ''); $this->setFilterCss('#' . self::$blockId . ' .wpfFilterLayoutVer>li {width:' . $width . '% !important;}'); } } } $filterName = $this->getFilterSetting($filter, 'name', ''); $isSlug = $this->getFilterSetting($filter, 'is_slugs', false) || ( !$this->getFilterSetting($filter, 'is_ids', false) && ( 'product_tag' == $filterName || 'product_brand' == $filterName || ( strpos($filterName, 'filter_') >= 0 && $this->getFilterSetting($filter, 'id', '') == 'wpfAttribute' ) ) ); $iconCollapsible = '<span class="wpfCollapsible">' . DispatcherWpf::applyFilters('getIconHtml', '+', 'categories_icon', $settings) . '</span>'; $collapseLevel = $this->getFilterSetting($filter['settings'], 'f_collapse_level', false); foreach ($filterItemList as $filterItem) { if ( !empty($excludeIds) && in_array($filterItem->term_id, $excludeIds) ) { continue; } if ( !empty($includeIds) && !in_array($filterItem->term_id, $includeIds) ) { continue; } if (!isset($filterItem->parent)) { $filterItem->parent = 0; } $termId = isset($filterItem->term_id) ? $filterItem->term_id : ''; $style = ''; $displayName = empty($filterItem->name_label) ? $filterItem->name : $filterItem->name_label; $addAttrs = $menuMode ? ' data-link="' . get_term_link($termId, 'product_cat') . '"' : ''; $hasChildren = ! empty( $filterItem->children ); $isChild = 0 != $filterItem->parent; if ( 'dropdown' === $type || 'mul_dropdown' === $type ) { $selected = ''; if ( is_array($selectedElem) && in_array($isSlug ? $filterItem->slug : $filterItem->term_id, $selectedElem) ) { $selected = 'selected'; } if ( is_array($showedTerms) && ( empty($showedTerms) || !in_array($filterItem->term_id, $showedTerms) ) ) { $style = ' display:none;'; } elseif ( ! $hideParent || ( $isChild && ( ! $hideAllParent || ! $hasChildren ) ) ) { self::$leer = false; } $slug = isset($filterItem->slug) ? urldecode($filterItem->slug) : ''; $name = isset($filterItem->name) ? urldecode($filterItem->name) : ''; $count = isset($filterItem->count) ? $filterItem->count : ''; if (!$allProductsFiltering) { $count = isset($countsTerms[$termId]) ? $countsTerms[$termId] : 0; } $countHtml = $showCount ? '<span class="wpfCount">(' . $count . ')</span>' : ''; if ( ! $hideParent || ( $isChild && ( ! $hideAllParent || ! $hasChildren ) ) ) { $img = ''; if ($showImage) { $metaSlug = $this->getTaxonomyOptionality($filterItem->taxonomy, 'thumbnail_id'); $thumbnail_id = get_term_meta($filterItem->term_id, $metaSlug, true); $img = wp_get_attachment_url($thumbnail_id); } if (!empty($style)) { $this->setFilterCss('#' . self::$blockId . ' [data-term-id="' . $termId . '"] {' . $style . '}'); } $html .= '<option data-term-name="' . $name . '" value="' . $termId . '" data-term-slug="' . $slug . '" data-count="' . $count . '" data-term-id="' . $termId . '" data-slug="' . $slug . '" ' . $selected . ' data-img="' . $img . '"' . $addAttrs . '>' . $pre . $displayName . ' ' . $countHtml . '</option>'; } if ( $hasChildren ) { $tmpPre = ( $isHierarchical && ! $hideAllParent ) ? $pre . '&nbsp;&nbsp;&nbsp;' : $pre; $html .= $this->generateTaxonomyOptionsHtml($filterItem->children, $selectedElem, $filter, false, $tmpPre, false, $includeIds, $showedTerms, $countsTerms); } } else { if ( is_array($showedTerms) && ( empty($showedTerms) || !in_array($filterItem->term_id, $showedTerms) ) ) { $style .= 'display:none;'; } elseif ( ! $hideParent || ( $isChild && ( ! $hideAllParent || ! $hasChildren ) ) ) { self::$leer = false; } $tagWrapper = ( 'text' !== $type && isset( $options['content_accessibility'] ) && '1' === $options['content_accessibility']['value'] ) ? 'div' : 'label'; if ( ! $hideParent || ( $isChild && ( ! $hideAllParent || ! $hasChildren ) ) ) { if (!empty($style)) { $this->setFilterCss('#' . self::$blockId . ' li[data-term-id="' . $filterItem->term_id . '"] {' . $style . '}'); } $hidePageCategoryClass = ( $filterItem->term_id === $currentCategoryId ) ? ' class="hidePageCategory"' : ''; $html .= '<li data-term-id="' . $filterItem->term_id . '" data-parent="' . $filterItem->parent . '" data-term-slug="' . urldecode($filterItem->slug) . '"' . $addAttrs . $hidePageCategoryClass . '>'; $html .= "<{$tagWrapper}" . ' class="wpfLiLabel">'; $checked = ''; if ( is_array($selectedElem) && in_array($isSlug ? $filterItem->slug : $filterItem->term_id, $selectedElem) ) { $checked = 'checked'; } $rand = rand(1, 99999); $checkId = 'wpfTaxonomyInputCheckbox' . $filterItem->term_id . $rand; $checkbox = '<span class="wpfCheckbox' . ( $isMulti ? ' wpfMulti' : '' ) . '"><input type="checkbox" id="' . $checkId . '" ' . $checked . '><label aria-label="' . esc_attr( $displayName ) . '" for="' . $checkId . '"></label></span>'; $html .= DispatcherWpf::applyFilters('getOneTaxonomyOptionHtml', $checkbox, array('type' => $type, 'id' => $checkId, 'checked' => $checked)); $html .= '<span class="wpfDisplay">'; $img = ''; if ($showImage) { $metaSlug = $this->getTaxonomyOptionality($filterItem->taxonomy, 'thumbnail_id'); $thumbnail_id = get_term_meta($filterItem->term_id, $metaSlug, true); $img = wp_get_attachment_image($thumbnail_id, $imgSize, false, array('alt' => $displayName)); $img = '<div class="wpfFilterTaxImgWrapper">' . $img . '</div>'; } $displayName = '<' . $titleTag . ' class="wpfFilterTaxNameWrapper">' . $displayName . '</' . $titleTag . '>'; $html .= '<span class="wpfValue">' . $img . $displayName . '</span>'; if ($showCount) { $count = isset($filterItem->count) ? $filterItem->count : ''; if (!$allProductsFiltering) { $count = isset($countsTerms[$termId]) ? $countsTerms[$termId] : 0; } $html .= '<span class="wpfCount">(' . $count . ')</span>'; } $html .= '</span>'; if ( ( ! $collapseLevel || $itemLevel >= $collapseLevel ) && ! empty( $isCollapsible ) && $hasChildren && $isHierarchical ) { $html .= $iconCollapsible; } $html .= "</{$tagWrapper}>"; } if ($hasChildren) { $tmpPre = ( $isHierarchical && ! $hideAllParent ) ? $pre . '&nbsp;&nbsp;&nbsp;' : $pre; if ( $isHierarchical && !$hideParent ) { $html .= '<ul' . ( ( ( $collapseLevel && $itemLevel < $collapseLevel ) || empty( $isCollapsible ) || $hideAllParent ) ? '' : ' class="wpfHidden"' ) . '>'; } elseif ( $isHierarchical && $hideParent && 0 != $filterItem->parent ) { $html .= '<ul class="wpfHideParent' . ( $hideAllParent ? ' wpfHideAllParent' : ( empty( $isCollapsible ) ? '' : ' wpfHidden' ) ) . '">'; } $childrenLevel = $itemLevel+1; $html .= $this->generateTaxonomyOptionsHtml($filterItem->children, $selectedElem, $filter, $excludeIds, $tmpPre, false, $includeIds, $showedTerms, $countsTerms, $childrenLevel); if ( $isHierarchical && !$hideParent ) { $html .= '</ul>'; } elseif ( $isHierarchical && $hideParent && 0 != $filterItem->parent ) { $html .= '</ul>'; } } if ( ! $hideParent || ( $isChild && ( ! $hideAllParent || ! $hasChildren ) ) ) { $html .= '</li>'; } } } $this->setLeerFilter(self::$leer); return $html; } private function generatePriceRangeOptionsHtml( $filter, $ranges, $layout ) { $html = ''; $isPro = FrameWpf::_()->isPro(); $options = FrameWpf::_()->getModule( 'options' )->getModel( 'options' )->getAll(); $minValue = ReqWpf::getVar('wpf_min_price'); $maxValue = ReqWpf::getVar('wpf_max_price'); $urlRange = $minValue . ',' . $maxValue; $type = $filter['settings']['f_frontend_type']; $underOver = $isPro && $this->getFilterSetting($filter['settings'], 'f_under_over', false); if ($underOver) { $underText = $this->getFilterSetting($filter['settings'], 'f_under_text', esc_attr__('Under', 'woo-product-filter')) . ' '; $overText = $this->getFilterSetting($filter['settings'], 'f_over_text', esc_attr__('Over', 'woo-product-filter')) . ' '; } if ('list' === $type) { if ($layout['is_ver']) { if ($layout['cnt'] > 1) { $width = number_format(100 / $layout['cnt'], 4, '.', ''); $this->setFilterCss('#' . self::$blockId . ' .wpfFilterLayoutVer li {width:' . $width . '%;}'); } } $isList = true; } elseif ('dropdown' === $type) { $html .= '<select>'; if (!empty($filter['settings']['f_dropdown_first_option_text'])) { $html .= '<option value="" data-slug="">' . esc_html__($filter['settings']['f_dropdown_first_option_text'], 'woo-product-filter') . '</option>'; } else { $html .= '<option value="" data-slug="">' . esc_html__('Select all', 'woo-product-filter') . '</option>'; } $isList = false; } else { return ''; } $module = FrameWpf::_()->getModule('woofilters'); $isCustom = true; if (function_exists( 'alg_wc_currency_switcher_plugin' )) { add_filter( 'raw_woocommerce_price', array(alg_wc_currency_switcher_plugin()->core, 'change_price_by_currency')); } $tagWrapper = ( isset( $options['content_accessibility'] ) && '1' === $options['content_accessibility']['value'] ) ? 'div' : 'label'; foreach ($ranges as $range) { if ( !empty($range['1']) && isset($range['0']) ) { if ( 'i' === $range[0] && !$underOver ) { $range[0] = 0; } if ( 'i' === $range[1] && ( !$underOver || 'i' === $range[0] ) ) { $price = self::$filterExistsPrices; $range[1] = $price->wpfMaxPrice; } // some plugin uses a different hook, use it if the standard one did not change the price if ( is_plugin_active( 'woocommerce-currency-switcher/index.php' ) || is_plugin_active( 'woocommerce-multicurrency/woocommerce-multicurrency.php' ) ) { $wc_price[0] = apply_filters( 'woocommerce_product_get_regular_price', $range[0], null ); $wc_price[1] = apply_filters( 'woocommerce_product_get_regular_price', $range[1], null ); } else { $wc_price = $range; } $priceRange = ( 'i' === $wc_price[0] ? $underText . wc_price($wc_price[1] + 0.01) : ( 'i' === $wc_price[1] ? $overText . wc_price( $wc_price[0] - 0.01 ) : wc_price( $wc_price[0] ) . ' - ' . wc_price( $wc_price[1] ) ) ); $priceRangeLabel = ( 'i' === $wc_price[0] ? $wc_price[1] + 0.01 : ( 'i' === $wc_price[1] ? $wc_price[0] - 0.01 : $wc_price[0] . ' - ' . $wc_price[1] ) ); $dataRange = ( 'i' === $range[0] ? '' : $module->getCurrencyPrice($range[0]) ) . ',' . ( 'i' === $range[1] ? '' : $module->getCurrencyPrice($range[1]) ); $selected = ( $dataRange === $urlRange ); if ($isList) { $html .= '<li data-range="' . $dataRange . '"><' . $tagWrapper . ' class="wpfLiLabel">'; $checkId = 'wpfPriceRangeCheckbox' . rand(1, 99999); $html .= '<span class="wpfCheckbox"><input type="checkbox" id="' . $checkId . '"' . ( $selected ? ' checked' : '' ) . '><label aria-label="' . esc_attr( $priceRangeLabel ) . '" for="' . $checkId . '"></label></span>'; $html .= '<span class="wpfDisplay"><span class="wpfValue">' . $priceRange . '</span></span>'; $html .= '</' . $tagWrapper . '></li>'; if ($selected) { $isCustom = false; } } else { $html .= '<option data-range="' . $dataRange . '"' . ( $selected ? ' selected' : '' ) . '>' . $priceRange . '</option>'; } } } if (function_exists( 'alg_wc_currency_switcher_plugin' )) { remove_filter( 'raw_woocommerce_price', array(alg_wc_currency_switcher_plugin()->core, 'change_price_by_currency')); } if ($isList) { if ($isPro && $this->getFilterSetting($filter['settings'], 'f_custom_fields', false)) { $customText = $this->getFilterSetting($filter['settings'], 'f_custom_text', esc_attr__('Custom', 'woo-product-filter')) . ' '; $selected = ( $isCustom && ( ',' != $urlRange ) ); $checkId = 'wpfPriceRangeCheckbox' . rand(1, 99999); $html .= '<li data-range="' . ( $selected ? $urlRange : '' ) . '"><' . $tagWrapper . ' class="wpfLiLabel">'; $html .= '<span class="wpfCheckbox wpfPriceCheckboxCustom"><input type="checkbox" id="' . $checkId . '"' . ( $selected ? ' checked' : '' ) . '><label aria-label="' . esc_attr( $customText ) . '" for="' . $checkId . '"></label></span>'; $html .= '<span class="wpfDisplay"><span class="wpfValue">' . $customText . '</span></span>'; $html .= '<span class="wpfPriceRangeCustom"><input class="passiveFilter" type="text" name="wpf_custom_min" value="' . ( $selected ? ReqWpf::getVar('wpf_min_price') : '' ) . '"> - <input class="passiveFilter" type="text" name="wpf_custom_max" value="' . ( $selected ? ReqWpf::getVar('wpf_max_price') : '' ) . '"><i class="fa fa-chevron-right"></i></span>'; $html .= '</' . $tagWrapper . '></li>'; } } else { $html .= '</select>'; } return $html; } private function generateLoaderHtml( $filterId, $settings ) { $settings = $this->getFilterSetting($settings, 'settings', array()); $colorPreview = $this->getFilterSetting($settings, 'filter_loader_icon_color', 'black'); $iconName = $this->getFilterSetting($settings, 'filter_loader_icon_name', 'default'); $iconNumber = $this->getFilterSetting($settings, 'filter_loader_icon_number', '0'); if (!FrameWpf::_()->isPro()) { $iconName = 'default'; } $htmlPreview = '<div class="wpfPreview wpfPreviewLoader wpfHidden">'; if ('custom' === $iconName) { $settings['is_overlay'] = false; $htmlPreview = DispatcherWpf::applyFilters('getCustomLoaderHtml', $htmlPreview, $settings); } elseif ( 'spinner' === $iconName || 'default' === $iconName ) { $htmlPreview .= '<div class="woobewoo-filter-loader spinner" ></div>'; } else { $this->setFilterCss('.wpfPreviewLoader .woobewoo-filter-loader {color: ' . $colorPreview . ';}'); $htmlPreview .= '<div class="woobewoo-filter-loader la-' . $iconName . ' la-2x">'; for ($i = 1; $i <= $iconNumber; $i++) { $htmlPreview .= '<div></div>'; } $htmlPreview .= '</div>'; } $htmlPreview .= '</div>'; return $htmlPreview; } public function wpfGetPageId() { global $wp_query, $post; $page_id = false; if ( is_home() && get_option('page_for_posts') ) { $page_id = get_option('page_for_posts'); } elseif ( is_front_page() && get_option('page_on_front') ) { $page_id = get_option('page_on_front'); } else { if ( function_exists('is_shop') && is_shop() && get_option('woocommerce_shop_page_id') != '' ) { $page_id = get_option('woocommerce_shop_page_id'); } else { if ( function_exists('is_cart') && is_cart() && get_option('woocommerce_cart_page_id') != '' ) { $page_id = get_option('woocommerce_cart_page_id'); } else { if ( function_exists('is_checkout') && is_checkout() && get_option('woocommerce_checkout_page_id') != '' ) { $page_id = get_option('woocommerce_checkout_page_id'); } else { if ( function_exists('is_account_page') && is_account_page() && get_option('woocommerce_myaccount_page_id') != '' ) { $page_id = get_option('woocommerce_myaccount_page_id'); } else { if ( $wp_query && !empty($wp_query->queried_object) && !empty($wp_query->queried_object->ID) ) { $page_id = $wp_query->queried_object->ID; } else { if (!empty($post->ID)) { $page_id = $post->ID; } } } } } } } return $page_id; } public function wpfCurrentLocation() { if (empty($_SERVER['HTTP_HOST'])) { return ''; } if ( ( isset($_SERVER['HTTPS']) && ( ( 'on' == $_SERVER['HTTPS'] ) || ( 1 == $_SERVER['HTTPS'] ) ) ) || ( isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && ( 'https' == $_SERVER['HTTP_X_FORWARDED_PROTO'] ) ) ) { $protocol = 'https://'; } else { $protocol = 'http://'; } $uri_parts = explode('?', ( empty($_SERVER['REQUEST_URI']) ? '' : sanitize_text_field($_SERVER['REQUEST_URI']) ), 2); return $protocol . sanitize_text_field($_SERVER['HTTP_HOST']) . $uri_parts[0]; } protected function getCatsByGetVar( $getVars, $slugs = true) { $cats = array(); foreach ($getVars as $getVar => $items) { if (strpos($getVar, 'wpf_filter_cat') !== false) { $ids = explode('|', $items); if (count($ids) <= 1) { $ids = explode(',', $items); } if ($slugs) { $cats = array_merge($cats, array_map(function( $id ) { return get_term_by('id', $id, 'product_cat', 'ARRAY_A')['slug']; }, $ids)); } else { $cats = array_merge($cats, $ids); } } } return $cats; } protected function existGetVarLike( $getVars, $field ) { foreach ($getVars as $getVar => $items) { if (strpos($getVar, $field) !== false) { return true; } } return false; } /** * Resolve post type product taxonomies dependency with standard product_cat * * @param string $taxonomySlug * @param string $metaSlug * * @return mix */ public function getTaxonomyOptionality( $taxonomySlug, $metaSlug ) { $meta_value = ''; if ('product_cat' == $taxonomySlug) { $meta_value = $metaSlug; } else { if (!empty($this->taxonomyOptionality[$taxonomySlug][$metaSlug])) { $meta_value = $this->taxonomyOptionality[$taxonomySlug][$metaSlug]; } } return $meta_value; } /** * Resolce depricated settings optionality * * @param string $settings * * @return string */ public function resolveDepricatedOptionality( $orderTab ) { $orderTab = json_decode($orderTab); if (is_array($orderTab)) { foreach ($orderTab as $key => $tab) { if ( empty($tab->settings->f_enable_title_mobile) && !empty($tab->settings->f_enable_title)) { $orderTab[$key]->settings->f_enable_title_mobile = $tab->settings->f_enable_title; } } } return json_encode($orderTab); } /** * Get filter settings with mobile breakpoin value * * @param array $settings * * @return string */ public function getMobileBreakpointValue( $filterSettings ) { $mobileBreakpointWidth = ''; $isMobileBreakpointWidth = $this->getFilterSetting( $filterSettings, 'desctop_mobile_breakpoint_switcher', false ); if ($isMobileBreakpointWidth) { $mobileBreakpointWidth = $this->getFilterSetting( $filterSettings, 'desctop_mobile_breakpoint_width', '' ); } return $mobileBreakpointWidth; } /** * Find if we need include children in taxonomy. * * @param bool $isHideChild * @param bool $isExtendParentFiltering * @param string $type * * @return bool */ public function findTaxonomyIncludeChildrenStatus( $isHideChild, $isExtendParentFiltering, $type ) { $typeWIthotHierarchyList = array( 'mul_dropdown', 'multi', 'buttons', 'text', ); $typeWithExtendParametrFilteringOption = array( 'list', 'dropdown', ); if ( ! $isHideChild && in_array($type, $typeWIthotHierarchyList)) { $isIncludeChildren = false; } else { $isIncludeChildren = true; } if (in_array($type, $typeWithExtendParametrFilteringOption)) { $isIncludeChildren = $isExtendParentFiltering; } return $isIncludeChildren; } public function renderSelectedFiltersHtml( $params ) { $id = isset($params['id']) ? (int) $params['id'] : 0; if (!$id) { return false; } $filter = $this->getModel('woofilters')->getById($id); if (!$filter) { return false; } $settings = unserialize($filter['setting_data'])['settings']; $isDisplayParams = $this->getFilterSetting($settings, 'display_selected_params', false); return $isDisplayParams ? '<div class="wpfSelectedParameters wpfHidden" data-filter="' . $id . '"></div>' : ''; } public function getChildrenOfIncludedCategories( $taxonomy, $categoryIds ) { //remove_all_filters('get_terms'); $output = array(); foreach ($categoryIds as $categoryId) { /*$args = array( 'child_of' => $categoryId, 'fields' => 'ids' ); $terms = get_terms($taxonomy, $args);*/ $terms = get_term_children($categoryId, $taxonomy); //this function is more faster if (!empty($terms)) { $output = array_merge($output, $terms); } } return array_merge($categoryIds, $output); } /** * Get pagination base structure * * @return array */ public function getPaginationBase() { $paginationBase = array(); $isShortcode = false; global $post; if (!empty($post->post_content)) { $isShortcode = has_shortcode( $post->post_content, 'products' ); } /** * Plugin compatibility * * @link https://www.elegantthemes.com/gallery/divi/ */ $theme = wp_get_theme(); if ('Divi' == $theme->name || 'Divi' == $theme->parent_theme) { if (!empty($post->post_content) && strpos($post->post_content, 'wp:divi/placeholder') !== false) { $paginationBase['base'] = 'product-page'; $paginationBase['type'] = 'shortcode'; return $paginationBase; } } if ($isShortcode) { $paginationBase['base'] = 'product-page'; $paginationBase['type'] = 'shortcode'; return $paginationBase; } else { $base = get_pagenum_link(999999999, false); } // pagination in a main url structure like /page/999999999/ if (strpos($base, '/999999999') !== false) { $queryUrlList = explode('/', $base); for ($i=0; $i < count($queryUrlList); $i++) { if (strpos($queryUrlList[$i], '999999999') !== false) { $paginationBase['type'] = 'url'; $paginationBase['base'] = $queryUrlList[$i-1]; } } // pagination in a query url structure like &paged=999999999 } else { $queryUrl = parse_url($base, PHP_URL_QUERY); $queryUrlList = explode('&', $queryUrl); foreach ($queryUrlList as $query) { if (strpos($query, '999999999') !== false) { $queryDelimiter = explode('=', $query); $paginationBase['base'] = $queryDelimiter[0]; $paginationBase['type'] = 'query'; } } } return $paginationBase; } /** * Set filter id */ public function setFitlerId() { return 'id="' . self::$blockId . '" data-order-key="' . self::$filterOrderKey . '" '; } /** * Set filter common data attributes * * @param array $filter * @param string $filterName * @param string $displayType * @param string $filterSlug * * @return void */ public function setCommonFitlerDataAttr( $filter, $filterName, $displayType, $filterSlug = '') { $filerList = FrameWpf::_()->getModule('woofilters')->getModel('woofilters')->getAllFilters(); $filterSlug = $filterSlug ? $filterSlug : $filerList[$filter['id']]['slug']; $filterContentType = $filerList[$filter['id']]['content_type']; return ' data-filter-type="' . $filter['id'] . '"' . ' data-get-attribute="' . $filterName . '"' . ( $displayType ? ' data-display-type="' . $displayType . '"' : '' ) . ( $filterContentType ? ' data-content-type="' . $filterContentType . '"' : '' ) . ( $filterSlug ? ' data-slug="' . $filterSlug . '"' : '' ) . ( empty($filter['uniqId']) ? '' : ' data-uniq-id="' . $filter['uniqId'] . '"' ) ; } public function getFilterUrlData( $filterName, $defFilterName = '' ) { $data = ReqWpf::getVar( $filterName ); if (is_null($data)) { preg_match( '/(filter_cat|filter_pwb|product_tag).*/', $filterName, $matches ); if ( isset( $matches[1] ) ) { $data = ReqWpf::getFilterRedirect( $matches[1] ); } } if (empty($data) || is_null($data)) { $data = DispatcherWpf::applyFilters('getFilterDefault', $data, empty($defFilterName) ? $filterName : $defFilterName); } return $data; } public function getMultiSelectHtml( $htmlOpt, $settings ) { $search = array( 'show' => $this->getFilterSetting( $settings, 'f_dropdown_search', 0 ), 'placeholder' => $this->getFilterSetting( $settings, 'f_dropdown_search_text', 'Search' ) ); $singleSelect = ( $this->getFilterSetting( $settings, 'f_single_select', false ) ) ? 'data-single-select' : ''; $hideCheckboxes = ( $this->getFilterSetting( $settings, 'f_hide_checkboxes', false ) ) ? 'data-hide-checkboxes' : ''; return '<select class="needsclick" multiple data-placeholder="' . esc_attr__( $this->getFilterSetting( $settings, 'f_dropdown_first_option_text', 'Select all' ), 'woo-product-filter' ) . '" data-search="' . esc_attr( json_encode( $search, JSON_UNESCAPED_UNICODE ) ) . '" ' . $singleSelect . ' ' . $hideCheckboxes . '>' . $htmlOpt . '</select>'; } }