* 3600 ); } else { $info[ $key ] = $value; } } $progressPercent = self::getProgressBarValue(); $logs = self::getLogs(); $isDetails = get_transient( self::DETAILS_DISPLAY_KEY ); $canBuildTaxonomyIndex = self::canBuildTaxonomyIndex(); $canBuildVendorsIndex = self::canBuildVendorsIndex(); ob_start(); include DGWT_WCAS_DIR . 'partials/admin/indexer-body.php'; $html = ob_get_contents(); ob_end_clean(); return $html; } /** * Check if can index taxonomies * * @return bool */ public static function canBuildTaxonomyIndex() { $showTerms = false; if ( DGWT_WCAS()->settings->getOption( 'show_matching_categories' ) === 'on' || DGWT_WCAS()->settings->getOption( 'show_matching_tags' ) === 'on' || DGWT_WCAS()->settings->getOption( 'show_matching_brands' ) === 'on' ) { $showTerms = true; } return $showTerms; } /** * Check if can index vendors * * @return bool */ public static function canBuildVendorsIndex() { return apply_filters( 'dgwt/wcas/search/vendors', false ); } /** * Check if can build variations index * * @return bool */ public static function canBuildVariationsIndex() { $canBuild = false; if ( ! empty( $_POST['dgwt_wcas_settings'] ) ) { $settings = $_POST['dgwt_wcas_settings']; if ( ! empty( $settings['search_in_product_sku'] ) && $settings['search_in_product_sku'] === 'on' ) { $canBuild = true; } } if ( ! $canBuild ) { $canBuild = DGWT_WCAS()->settings->getOption( 'search_in_product_sku' ) === 'on'; } return $canBuild; } /** * Check if index is completed and valid * * @param string $lang * * @return bool */ public static function isIndexValid( $lang = '' ) { global $wpdb; $valid = false; if ( self::getInfo( 'status' ) === 'completed' && self::searchableIndexExists( $lang ) && self::readableIndexExists() ) { $info = $wpdb->get_var( "SELECT ivalue FROM $wpdb->dgwt_wcas_si_info WHERE ikey = 'stemmer'" ); if ( ! empty( $info ) ) { $valid = true; } } return $valid; } /** * Get last index build info * * @return array */ public static function getLastBuildInfo() { global $wpdb; $data = array(); $opt = $wpdb->get_var( $wpdb->prepare( "SELECT SQL_NO_CACHE option_value FROM $wpdb->options WHERE option_name = %s", self::LAST_BUILD_OPTION_KEY ) ); if ( ! empty( $opt ) ) { $opt = @unserialize( $opt ); if ( is_array( $opt ) ) { $data = $opt; } } return $data; } /** * Wipe all data of deprecated SQLite driver * * @return void */ public static function wipeSQLiteAfterEffects() { $uploadDir = wp_upload_dir(); if ( ! empty( $uploadDir['basedir'] ) ) { $directory = $uploadDir['basedir'] . '/wcas-search'; $file = $uploadDir['basedir'] . '/wcas-search/products.index'; if ( file_exists( $file ) && is_writable( $file ) ) { @unlink( $file ); } if ( file_exists( $directory ) && is_writable( $directory ) ) { @rmdir( $directory ); } } } /** * Complete the search index * * @return void */ public static function maybeMarkAsCompleted() { $status = self::getInfo( 'status' ); $sEndTs = self::getInfo( 'end_searchable_ts' ); $rEndTs = self::getInfo( 'end_readable_ts' ); $tEndTs = self::canBuildTaxonomyIndex() ? self::getInfo( 'end_taxonomies_ts' ) : 1; $vEndTs = self::canBuildVariationsIndex() ? self::getInfo( 'end_variation_ts' ) : 1; if ( 'building' === $status && ! empty( $sEndTs ) && ! empty( $rEndTs ) && ! empty( $vEndTs ) && ! empty( $tEndTs ) ) { self::addInfo( 'status', 'completed' ); self::addInfo( 'end_ts', time() ); self::log( 'Indexing completed' ); do_action( 'dgwt/wcas/indexer/status/completed' ); } } /** * Remove all database tables created by this plugin * * @param bool $networkScope delete tables in whole network * * @return void */ public static function deleteIndexOptions( $networkScope = false ) { global $wpdb; $prefix = $wpdb->prefix; if ( is_multisite() && $networkScope ) { $prefix = $wpdb->base_prefix; } delete_option( self::LAST_BUILD_OPTION_KEY ); delete_transient( self::DETAILS_DISPLAY_KEY ); if ( is_multisite() && $networkScope ) { foreach ( get_sites() as $site ) { if ( is_numeric( $site->blog_id ) ) { $blogID = $site->blog_id == 1 ? '' : $site->blog_id . '_'; $table = $prefix . $blogID . 'options'; $wpdb->delete( $table, array( 'option_name' => self::LAST_BUILD_OPTION_KEY ) ); $wpdb->delete( $table, array( 'option_name' => '_transient_timeout_' . self::DETAILS_DISPLAY_KEY ) ); $wpdb->delete( $table, array( 'option_name' => '_transient_' . self::DETAILS_DISPLAY_KEY ) ); } } } } /** * Remove all database tables created by this plugin * * @param bool $networkScope delete tables in whole network * * @return void */ public static function deleteDatabaseTables( $networkScope = false ) { global $wpdb; // DB tables $tables = Utils::getAllPluginTables( $networkScope ); if ( ! empty( $tables ) ) { foreach ( $tables as $table ) { $wpdb->query( "DROP TABLE IF EXISTS $table" ); } } } /** * Removal of planned actions that will update products in the index */ public static function wipeActionScheduler() { $queue = Utils::getQueue(); if ( empty( $queue ) ) { return; } try { $queue->cancel_all( 'dgwt/wcas/tnt/background_product_update' ); } catch ( Exception $e ) { } } /** * Dispatch building variation index */ public static function maybeDispatchVariationAsyncProcess() { if ( ! self::canBuildVariationsIndex() ) { return; } $status = self::getInfo( 'status' ); $sEndTs = self::getInfo( 'end_searchable_ts' ); $rEndTs = self::getInfo( 'end_readable_ts' ); if ( ( Config::isIndexerMode( 'async' ) && $status === 'building' && ! empty( $rEndTs ) ) || ( Config::isIndexerMode( 'sync' ) && $status === 'building' && ! empty( $sEndTs ) && ! empty( $rEndTs ) ) || ( Config::isIndexerMode( 'direct' ) && $status === 'building' ) ) { self::addInfo( 'start_variation_ts', time() ); // Reset end time because this process may end several times self::addInfo( 'end_variation_ts', 0 ); self::log( '[Variation index] Building...' ); DGWT_WCAS()->tntsearchMySql->asynchBuildIndexV->maybe_dispatch(); } } /** * Dispatch building taxonomies index */ public static function maybeDispatchTaxonomyAsyncProcess() { if ( ! self::canBuildTaxonomyIndex() ) { self::maybeDispatchVariationAsyncProcess(); return; } $status = self::getInfo( 'status' ); $rEndTs = self::getInfo( 'end_readable_ts' ); if ( ( Config::isIndexerMode( 'async' ) && $status === 'building' && ! empty( $rEndTs ) ) || ( Config::isIndexerMode( 'sync' ) && $status === 'building' && ! empty( $rEndTs ) ) || ( Config::isIndexerMode( 'direct' ) && $status === 'building' ) ) { RequestT::handle(); } } /** * Check if the indexer working too long without any action * * @return bool */ public static function isIndexerWorkingTooLong() { $status = Builder::getInfo( 'status' ); // Return early if indexer is not working if ( ! in_array( $status, array( 'building', 'preparing' ) ) ) { return false; } $lastActionTs = absint( Builder::getInfo( 'last_action_ts' ) ); // Return early if the indexer info hasn't been created yet if ( empty( $lastActionTs ) ) { return false; } $diff = time() - $lastActionTs; $maxNoActionTime = defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON ? 61 * MINUTE_IN_SECONDS : 16 * MINUTE_IN_SECONDS; /** * Filters maximum no action time of indexer. * * @param int $maxNoActionTime Max time in seconds. 16 min if WP-Cron is enabled or 61 min if not */ $maxNoActionTime = apply_filters( 'dgwt/wcas/indexer/max_no_action_time', $maxNoActionTime ); return in_array( $status, array( 'building', 'preparing' ) ) && $diff >= $maxNoActionTime; } }