\]#i',
// Replace `true` with `!0`
'#(?<=return |[=:,\(\[])true\b#',
// Replace `false` with `!1`
'#(?<=return |[=:,\(\[])false\b#',
// Clean up ...
'#\s*(\/\*|\*\/)\s*#'
), array(
'$1',
'$1$2',
'}',
'$1$3',
'$1.$3',
'!0',
'!1',
'$1'
), $input );
}
/**
* Minify CSS
*
* @see https://gist.github.com/tovic/d7b310dea3b33e4732c0
*
* @param string
*
* @return string
*/
public static function minifyCSS( $input ) {
if ( trim( $input ) === "" ) {
return $input;
}
// Force white-space(s) in `calc()`
if ( strpos( $input, 'calc(' ) !== false ) {
$input = preg_replace_callback( '#(?<=[\s:])calc\(\s*(.*?)\s*\)#', function ( $matches ) {
return 'calc(' . preg_replace( '#\s+#', "\x1A", $matches[1] ) . ')';
}, $input );
}
return preg_replace(
array(
// Remove comment(s)
'#("(?:[^"\\\]++|\\\.)*+"|\'(?:[^\'\\\\]++|\\\.)*+\')|\/\*(?!\!)(?>.*?\*\/)|^\s*|\s*$#s',
// Remove unused white-space(s)
'#("(?:[^"\\\]++|\\\.)*+"|\'(?:[^\'\\\\]++|\\\.)*+\'|\/\*(?>.*?\*\/))|\s*+;\s*+(})\s*+|\s*+([*$~^|]?+=|[{};,>~+]|\s*+-(?![0-9\.])|!important\b)\s*+|([[(:])\s++|\s++([])])|\s++(:)\s*+(?!(?>[^{}"\']++|"(?:[^"\\\]++|\\\.)*+"|\'(?:[^\'\\\\]++|\\\.)*+\')*+{)|^\s++|\s++\z|(\s)\s+#si',
// Replace `0(cm|em|ex|in|mm|pc|pt|px|vh|vw|%)` with `0`
'#(?<=[\s:])(0)(cm|em|ex|in|mm|pc|pt|px|vh|vw|%)#si',
// Replace `:0 0 0 0` with `:0`
'#:(0\s+0|0\s+0\s+0\s+0)(?=[;\}]|\!important)#i',
// Replace `background-position:0` with `background-position:0 0`
'#(background-position):0(?=[;\}])#si',
// Replace `0.6` with `.6`, but only when preceded by a white-space or `=`, `:`, `,`, `(`, `-`
'#(?<=[\s=:,\(\-]|&\#32;)0+\.(\d+)#s',
// Minify string value
'#(\/\*(?>.*?\*\/))|(?.*?\*\/))|(\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
FROM $wpdb->postmeta as pm
INNER JOIN $wpdb->posts as p ON p.ID = pm.post_id
WHERE p.post_type = 'product'
AND pm.meta_value NOT LIKE 'field_%'
AND pm.meta_value NOT LIKE 'a:%'
AND pm.meta_value NOT LIKE '%\%\%%'
AND pm.meta_value NOT LIKE '_oembed_%'
AND pm.meta_value NOT REGEXP '^1[0-9]{9}'
AND pm.meta_value NOT IN ('1','0','-1','no','yes','[]', '')
";
$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();
$sql = $wpdb->prepare( "SHOW TABLES LIKE %s", $tableName );
if ( ! empty( $wpdb->get_var( $sql ) ) ) {
$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 );
}
/**
* Remove batch options
*
* @return void
*/
public static function removeBatchOptions__premium_only() {
global $wpdb;
if ( dgoraAsfwFs()->is__premium_only() ) {
/**
* Searchable and readable index batch
* Samples:
* - wcas_build_readable_index_batch_bfc6f612423866e94a9fd52889a635b8
* - wcas_build_searchable_index_batch_bfc6f612423866e94a9fd52889a635b8
*/
$table = $wpdb->options;
$column = 'option_name';
if ( is_multisite() ) {
$table = $wpdb->sitemeta;
$column = 'meta_key';
}
$wpdb->query( "
DELETE
FROM {$table}
WHERE {$column} LIKE '%_index_batch_%'
OR {$column} LIKE '%wcas_build_readable%'
OR {$column} LIKE '%wcas_build_searchable%'
OR {$column} LIKE '%wcas_build_variation%'
OR {$column} LIKE '%wcas_build_taxonomy%'
" );
}
}
/**
* 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 HTML question mark with tooltip
*
* @param string $id
* @param string $content
* @param string $template
*
* @return string
*/
public static function createQuestionMark( $id, $content = '', $template = '', $placement = 'top' ) {
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;
}
/**
* 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( $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() {
$labels = apply_filters( 'dgwt/wcas/labels', array(
'category' => __( 'Category', 'woocommerce' ),
'tag' => __( 'Tag' ),
'brand' => __( 'Brand', 'ajax-search-for-woocommerce' ),
'post' => __( 'Post' ),
'page' => __( 'Page' ),
'vendor' => __( 'Vendor', 'ajax-search-for-woocommerce' ),
'product_cat_plu' => __( 'Categories', 'woocommerce' ),
'product_tag_plu' => __( 'Tags' ),
'product_plu' => __( 'Products', 'woocommerce' ),
'brand_plu' => __( 'Brands', 'ajax-search-for-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', '' )
) );
return $labels;
}
/**
* 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