\s\\{\\}\\];,])#si',
'#(\\/\\*(?>.*?\\*\\/))|(\\burl\\()([\'"])([^\\s]+?)\\3(\\))#si',
// Minify HEX color code
'#(?<=[\\s=:,\\(]\\#)([a-f0-6]+)\\1([a-f0-6]+)\\2([a-f0-6]+)\\3#i',
// Replace `(border|outline):none` with `(border|outline):0`
'#(?<=[\\{;])(border|outline):none(?=[;\\}\\!])#',
// Remove empty selector(s)
'#(\\/\\*(?>.*?\\*\\/))|(^|[\\{\\}])(?:[^\\s\\{\\}]+)\\{\\}#s',
'#\\x1A#',
), array(
'$1',
'$1$2$3$4$5$6$7',
'$1',
':0',
'$1:0 0',
'.$1',
'$1$3',
'$1$2$4$5',
'$1$2$3',
'$1:0',
'$1$2',
' '
), $input );
}
/**
* Compare WooCommerce function
*
* @param $version
* @param $op
*
* @return bool
*/
public static function compareWcVersion( $version, $op )
{
if ( function_exists( 'WC' ) && version_compare( WC()->version, $version, $op ) ) {
return true;
}
return false;
}
/**
* Check if is settings page
* @return bool
*/
public static function isSettingsPage()
{
if ( is_admin() && !empty($_GET['page']) && $_GET['page'] === 'dgwt_wcas_settings' ) {
return true;
}
return false;
}
/**
* Check if is debug page
* @return bool
*/
public static function isDebugPage()
{
if ( is_admin() && !empty($_GET['page']) && $_GET['page'] === 'dgwt_wcas_debug' ) {
return true;
}
return false;
}
/**
* Check if is Freemius checkout page
* @return bool
*/
public static function isCheckoutPage()
{
if ( is_admin() && !empty($_GET['page']) && $_GET['page'] === 'dgwt_wcas_settings-pricing' ) {
return true;
}
return false;
}
/**
* Get settings URL
*
* @return string
*/
public static function getSettingsUrl()
{
return admin_url( 'admin.php?page=dgwt_wcas_settings' );
}
/**
* Get total products
*
* @return int
*/
public static function getTotalProducts()
{
global $wpdb ;
$sql = "SELECT COUNT(ID) FROM {$wpdb->posts} WHERE post_type = 'product' AND post_status = 'publish'";
$total = $wpdb->get_var( $sql );
return absint( $total );
}
/**
* Get all products IDs
* @return array
*/
public static function getProductsForIndex()
{
global $wpdb ;
$sql = "SELECT ID FROM {$wpdb->posts} WHERE post_type = 'product' AND post_status = 'publish' ORDER BY ID ASC";
$ids = $wpdb->get_col( $sql );
if ( !is_array( $ids ) || empty($ids[0]) || !is_numeric( $ids[0] ) ) {
$ids = array();
}
return $ids;
}
/**
* Get readable format of memory
*
* @param int $bytes
*
* @return string
*/
public static function getReadableMemorySize( $bytes )
{
$unit = array(
'b',
'kb',
'mb',
'gb',
'tb',
'pb'
);
return @round( $bytes / pow( 1024, $i = floor( log( $bytes, 1024 ) ) ), 2 ) . ' ' . $unit[$i];
}
/**
* Get pro icon/label
*
* @param string $label
* @param string $type
* @param string $headerSubtitle
*
* @return string
*/
public static function getSettingsProLabel( $label, $type = 'header', $headerSubtitle = '' )
{
$html = '';
switch ( $type ) {
case 'header':
if ( !empty($headerSubtitle) ) {
$label = '';
}
$html .= '
';
break;
case 'option-label':
$html .= '' . $label . '' . __( 'Pro', 'ajax-search-for-woocommerce' ) . '
';
break;
}
return $html;
}
/**
* Calc score for searched
*
* @param string $searched
* @param string $string eg. product title
* @param array $args
*
* @return int
*/
public static function calcScore( $searched, $string, $args = array() )
{
$score = 0;
if ( empty($searched) || empty($string) ) {
return $score;
}
$default = array(
'check_similarity' => true,
'check_position' => true,
'score_containing' => 50,
);
$args = array_merge( $default, $args );
$searched = mb_strtolower( $searched );
$string = mb_strtolower( $string );
if ( $args['check_similarity'] ) {
$m = similar_text( $searched, $string, $percent );
$score = ($score + $percent) / 3;
}
$pos = strpos( $string, $searched );
// Add score based on substring position
if ( $pos !== false ) {
$score += $args['score_containing'];
// Bonus for contained substring
// Bonus for substring position
if ( $args['check_position'] ) {
$posBonus = (100 - $pos * 100 / strlen( $string )) / 2;
$score += $posBonus;
}
// Bonus for exact match
if ( $string === $searched ) {
$score += $args['score_containing'] * 5;
}
}
return $score;
}
/**
* Sorting by score
*
* @param $a
* @param $b
*
* @return int
*/
public static function cmpSimilarity( $a, $b )
{
$scoreA = 0;
$scoreB = 0;
if ( is_object( $a ) ) {
$scoreA = $a->score;
$scoreB = $b->score;
}
if ( is_array( $a ) ) {
$scoreA = $a['score'];
$scoreB = $b['score'];
}
if ( $scoreA == $scoreB ) {
return 0;
}
return ( $scoreA < $scoreB ? 1 : -1 );
}
/**
* Sorting by search resutls groups priority
*
* @param $a
* @param $b
*
* @return int
*/
public static function sortAjaxResutlsGroups( $a, $b )
{
if ( $a['order'] == $b['order'] ) {
return 0;
}
return ( $a['order'] < $b['order'] ? -1 : 1 );
}
/**
* Sort from the longest to the shortest
*
* @param $a
* @param $b
*
* @return int
*/
public static function sortFromLongest( $a, $b )
{
$la = mb_strlen( $a );
$lb = mb_strlen( $b );
if ( $la == $lb ) {
return strcmp( $b, $a );
}
return $lb - $la;
}
/**
* Get taxonomy parents
*
* @param int $term_id
* @param string $taxonomy
*
* @return string
*/
public static function getTermBreadcrumbs(
$termID,
$taxonomy,
$visited = array(),
$lang = '',
$exclude = array()
)
{
$chain = '';
$separator = ' > ';
if ( Multilingual::isMultilingual() ) {
$parent = Multilingual::getTerm( $termID, $taxonomy, $lang );
} else {
$parent = get_term( $termID, $taxonomy );
}
if ( empty($parent) || !isset( $parent->name ) ) {
return '';
}
$name = $parent->name;
if ( $parent->parent && $parent->parent != $parent->term_id && !in_array( $parent->parent, $visited ) ) {
$visited[] = $parent->parent;
$chain .= self::getTermBreadcrumbs(
$parent->parent,
$taxonomy,
$visited,
$lang
);
}
if ( !in_array( $parent->term_id, $exclude ) ) {
$chain .= $name . $separator;
}
return $chain;
}
/**
* Get taxonomies of products attributes
*
* @return array
*
*/
public static function getAttributesTaxonomies()
{
$taxonomies = array();
$attributeTaxonomies = wc_get_attribute_taxonomies();
if ( !empty($attributeTaxonomies) ) {
foreach ( $attributeTaxonomies as $taxonomy ) {
$taxonomies[] = 'pa_' . $taxonomy->attribute_name;
}
}
return apply_filters( 'dgwt/wcas/attribute_taxonomies', $taxonomies );
}
/**
*
*/
public static function canInstallPremium()
{
}
/**
* Get indexer demo HTML
*
* @return string
*/
public static function indexerDemoHtml()
{
$html = '';
ob_start();
include DGWT_WCAS_DIR . 'partials/admin/indexer-header-demo.php';
$html .= ob_get_clean();
return $html;
}
/**
* Get features HTML
*
* @return string
*/
public static function featuresHtml()
{
$html = '';
ob_start();
include DGWT_WCAS_DIR . 'partials/admin/features.php';
$html .= ob_get_clean();
return $html;
}
/**
* Get searchable custom fields keys
*
* @return array
*/
public static function getSearchableCustomFields()
{
global $wpdb ;
$customFields = array();
$excludedMetaKeys = array(
'_sku',
'_wp_old_date',
'_tax_status',
'_stock_status',
'_product_version',
'_smooth_slider_style',
'auctioninc_calc_method',
'auctioninc_pack_method',
'_thumbnail_id',
'_product_image_gallery',
'pdf_download',
'slide_template',
'cad_iframe',
'downloads',
'edrawings_file',
'3d_pdf_download',
'3d_pdf_render',
'_original_id'
);
$excludedMetaKeys = apply_filters( 'dgwt/wcas/indexer/excluded_meta_keys', $excludedMetaKeys );
$sql = "SELECT DISTINCT meta_key\n FROM {$wpdb->postmeta} as pm\n INNER JOIN {$wpdb->posts} as p ON p.ID = pm.post_id\n WHERE p.post_type = 'product'\n AND pm.meta_value NOT LIKE 'field_%'\n AND pm.meta_value NOT LIKE 'a:%'\n AND pm.meta_value NOT LIKE '%\\%\\%%'\n AND pm.meta_value NOT LIKE '_oembed_%'\n AND pm.meta_value NOT REGEXP '^1[0-9]{9}'\n AND pm.meta_value NOT IN ('1','0','-1','no','yes','[]', '')\n ";
$metaKeys = $wpdb->get_col( $sql );
if ( !empty($metaKeys) ) {
foreach ( $metaKeys as $metaKey ) {
if ( !in_array( $metaKey, $excludedMetaKeys ) && self::keyIsValid( $metaKey ) ) {
$label = $metaKey;
//@TODO Recognize labels based on meta key or public known as Yoast SEO etc.
$customFields[] = array(
'label' => $label,
'key' => $label,
);
}
}
}
$customFields = array_reverse( $customFields );
return apply_filters( 'dgwt/wcas/indexer/searchable_custom_fields', $customFields );
}
/**
* Check if key is valid
*
* @param $key
*
* @return bool
*/
public static function keyIsValid( $key )
{
return !preg_match( '/[^\\p{L}\\p{N}\\:\\.\\_\\s\\-]+/u', $key );
}
/**
* Check if table exist
*
* @return bool
*/
public static function isTableExists( $tableName )
{
global $wpdb ;
$exist = false;
$wpdb->hide_errors();
if ( empty($tableName) ) {
return false;
}
$sql = $wpdb->prepare( "SHOW TABLES LIKE %s", $wpdb->prefix . 'dgwt_wcas_%' );
$result = $wpdb->get_col( $sql );
if ( is_array( $result ) && in_array( $tableName, $result ) ) {
$exist = true;
}
return $exist;
}
/**
* Check if the engine can search in variable products
*
* @return bool
*/
public static function canSearchInVariableProducts()
{
global $wpdb ;
$allow = false;
$el = $wpdb->get_var( "SELECT ID FROM {$wpdb->posts} WHERE post_type = 'product_variation' LIMIT 1" );
if ( !empty($el) && is_numeric( $el ) ) {
$allow = true;
}
if ( DGWT_WCAS()->settings->getOption( 'search_in_product_content' ) !== 'on' ) {
$allow = false;
}
return apply_filters( 'dgwt/wcas/search_in_variable_products', $allow );
}
/**
* Allow to remove method for an hook when, it's a class method used and class don't have variable, but you know the class name
*
* @link https://github.com/herewithme/wp-filters-extras
* @return bool
*/
public static function removeFiltersForAnonymousClass(
$hook_name = '',
$class_name = '',
$method_name = '',
$priority = 0
)
{
global $wp_filter ;
// Take only filters on right hook name and priority
if ( !isset( $wp_filter[$hook_name][$priority] ) || !is_array( $wp_filter[$hook_name][$priority] ) ) {
return false;
}
// Loop on filters registered
foreach ( (array) $wp_filter[$hook_name][$priority] as $unique_id => $filter_array ) {
// Test if filter is an array ! (always for class/method)
if ( isset( $filter_array['function'] ) && is_array( $filter_array['function'] ) ) {
// Test if object is a class, class and method is equal to param !
if ( is_object( $filter_array['function'][0] ) && get_class( $filter_array['function'][0] ) && get_class( $filter_array['function'][0] ) == $class_name && $filter_array['function'][1] == $method_name ) {
// Test for WordPress >= 4.7 WP_Hook class (https://make.wordpress.org/core/2016/09/08/wp_hook-next-generation-actions-and-filters/)
if ( is_a( $wp_filter[$hook_name], 'WP_Hook' ) ) {
unset( $wp_filter[$hook_name]->callbacks[$priority][$unique_id] );
} else {
unset( $wp_filter[$hook_name][$priority][$unique_id] );
}
}
}
}
return false;
}
/**
* Create tooltip
*
* @param string $id
* @param string $content
* @param string $template
* @param string $placement
* @param string $class
*
* @return string
*/
public static function createTooltip(
$id,
$content = '',
$template = '',
$placement = 'right',
$class = ''
)
{
if ( !empty($template) ) {
$file = DGWT_WCAS_DIR . 'partials/admin/tooltips/' . $template . '.php';
if ( file_exists( $file ) ) {
ob_start();
require $file;
$content = ob_get_contents();
ob_end_clean();
}
}
$id = 'js-dgwt-wcas-tooltip-id' . sanitize_key( $id );
$html = '';
$html .= '';
return $html;
}
/**
* Create HTML override option tooltip
*
* @param string $id
* @param string $content
* @param string $template
* @param string $placement
*
* @return string
*/
public static function getOverrideOptionText( $theme )
{
$linkToShortcodesDoc = 'https://fibosearch.com/documentation/get-started/how-to-add-fibosearch-to-your-website/#add-fibosearch-with-a-shortcode';
$content = '' . sprintf( __( 'This option is overridden by the seamless integration with the %s theme. If you want to change the value of this option, disable the integration in
WooCommerce -> FiboSearch -> Starting (tab).', 'ajax-search-for-woocommerce' ), $theme ) . '
';
$content .= '' . sprintf( __( 'Furthermore, you can override this option for a specific search bar via shortcode params. Learn more about shortcodes parameters.', 'ajax-search-for-woocommerce' ), $linkToShortcodesDoc ) . '
';
return $content;
}
/**
* Create HTML question mark with tooltip
*
* @param string $id
* @param string $content
* @param string $template
* @param string $placement
*
* @return string
*/
public static function createQuestionMark(
$id,
$content = '',
$template = '',
$placement = 'right'
)
{
return self::createTooltip(
$id,
$content,
$template,
$placement,
'dashicons dashicons-editor-help dgwt-wcas-questio-mark'
);
}
/**
* Create HTML option override tooltip
*
* @param string $id
* @param string $content
* @param string $template
* @param string $placement
*
* @return string
*/
public static function createOverrideTooltip(
$id,
$content = '',
$template = '',
$placement = 'right'
)
{
return self::createTooltip(
$id,
$content,
$template,
$placement,
'dashicons dashicons-lock dgwt-wcas-override-tooltip'
);
}
/**
* Get list of 24 hours
*/
public static function getHours()
{
$hours = array();
$cycle12 = ( get_option( 'time_format' ) === 'H:i' ? false : true );
for ( $i = 0 ; $i < 24 ; $i++ ) {
$label = ( $cycle12 ? $i . ':00 am' : $i . ':00' );
if ( $cycle12 && $i === 0 ) {
$label = 12 . ':00 am';
}
if ( $cycle12 && $i > 11 ) {
if ( $i === 12 ) {
$label = 12 . ':00 pm';
} else {
$label = $i - 12 . ':00 pm';
}
}
$hours[$i] = $label;
}
return $hours;
}
/**
* Get local date including timezone
*
* @param $timestamp
* @param string $format
*
* @return string
* @throws \Exception
*/
public static function localDate( $timestamp, $format = '' )
{
if ( empty($timestamp) ) {
return '';
}
if ( empty($format) ) {
$format = get_option( 'date_format' ) . ' ' . get_option( 'time_format' );
}
$date = new \WC_DateTime( "@{$timestamp}" );
$date->setTimezone( new \DateTimeZone( wc_timezone_string() ) );
return $date->date_i18n( $format );
}
/**
* Get labels
*
* @return array
*/
public static function getLabels()
{
return apply_filters( 'dgwt/wcas/labels', array(
'post' => __( 'Post' ),
'page' => __( 'Page' ),
'vendor' => __( 'Vendor', 'ajax-search-for-woocommerce' ),
'product_plu' => __( 'Products', 'woocommerce' ),
'post_plu' => __( 'Posts' ),
'page_plu' => __( 'Pages' ),
'vendor_plu' => __( 'Vendors', 'ajax-search-for-woocommerce' ),
'sku_label' => __( 'SKU', 'woocommerce' ) . ':',
'sale_badge' => __( 'Sale', 'woocommerce' ),
'vendor_sold_by' => __( 'Sold by:', 'ajax-search-for-woocommerce' ),
'featured_badge' => __( 'Featured', 'woocommerce' ),
'in' => _x( 'in', 'in categories fe. in Books > Crime stories', 'ajax-search-for-woocommerce' ),
'read_more' => __( 'continue reading', 'ajax-search-for-woocommerce' ),
'no_results' => DGWT_WCAS()->settings->getOption( 'search_no_results_text', __( 'No results', 'ajax-search-for-woocommerce' ) ),
'show_more' => DGWT_WCAS()->settings->getOption( 'search_see_all_results_text', __( 'See all products...', 'ajax-search-for-woocommerce' ) ),
'show_more_details' => DGWT_WCAS()->settings->getOption( 'search_see_all_results_text', __( 'See all products...', 'ajax-search-for-woocommerce' ) ),
'search_placeholder' => DGWT_WCAS()->settings->getOption( 'search_placeholder', __( 'Search for products...', 'ajax-search-for-woocommerce' ) ),
'submit' => DGWT_WCAS()->settings->getOption( 'search_submit_text', '' ),
) );
}
/**
* Get labels
*
* @param string $key
*
* @return string
*/
public static function getLabel( $key )
{
$label = '';
$labels = self::getLabels();
if ( array_key_exists( $key, $labels ) ) {
$label = $labels[$key];
}
return $label;
}
/**
* Remove all HTML tags including