function settings_license_nag()
    {
        $nag = $this->implement_nag(array('name' => 'license', 'nonce' => 'searchwpnagnnonce'));
        $searchwp = SWP();
        $notices = searchwp_get_setting('notices');
        $initial_notified = is_array($notices) && in_array('initial', $notices) ? true : false;
        if (false == $initial_notified && !empty($searchwp->license) && (isset($searchwp->status) && 'valid' !== $searchwp->status) && !$nag['dismissed'] && apply_filters('searchwp_initial_license_nag', true)) {
            ?>
			<div id="setting-error-settings_updated" class="updated settings-error swp-license-nag">
				<p><?php 
            _e('In order to receive updates and support, you must have an active license.', 'searchwp');
            ?>
 <a href="<?php 
            echo esc_url(add_query_arg(array('page' => 'searchwp', 'tab' => 'license'), admin_url('options.php')));
            ?>
"><?php 
            _e('Manage License', 'searchwp');
            ?>
</a> <a href="<?php 
            echo esc_url(SEARCHWP_EDD_STORE_URL);
            ?>
"><?php 
            _e('Purchase License', 'searchwp');
            ?>
</a> <a href="<?php 
            echo esc_url($nag['dismissal_link']);
            ?>
"><?php 
            _e('Dismiss', 'searchwp');
            ?>
</a></p>
			</div>
		<?php 
        }
    }
    /**
     * If the debug log is over 2MB
     */
    function log_file_size_warning()
    {
        $searchwp = SWP();
        $logfile = trailingslashit($searchwp->dir) . 'debug.log';
        // if the logfile is over a 2MB it's likely the developer forgot to disable debugging
        if (file_exists($logfile) && absint(filesize($logfile)) > 2097151) {
            ?>
			<div class="error" id="searchwp-log-file-size">
				<p><?php 
            _e('Your SearchWP debug log is quite large. Please remember to disable debugging and delete <code>~/wp-content/plugins/searchwp/debug.log</code> when you are done.', 'searchwp');
            ?>
</p>
			</div>
		<?php 
        }
    }
 /**
  * Perform initial Extension setup
  *
  * @since 1.3.1
  */
 function prime_extensions()
 {
     $searchwp = SWP();
     // implement extensions
     $this->extensions = apply_filters('searchwp_extensions', array());
     if (is_array($this->extensions) && !empty($this->extensions)) {
         foreach ($this->extensions as $extension => $path) {
             $class_name = 'SearchWP' . $extension;
             if (!class_exists($class_name) && file_exists($path)) {
                 /** @noinspection PhpIncludeInspection */
                 include_once $path;
             }
             $this->extensions[$extension] = new $class_name($this);
             // add plugin row action
             if (isset($this->extensions[$extension]->min_searchwp_version) && version_compare($searchwp->version, $this->extensions[$extension]->min_searchwp_version, '<')) {
                 do_action('searchwp_log', 'after_plugin_row_' . plugin_basename($path));
                 add_action('after_plugin_row_' . plugin_basename($path), array($this, 'plugin_row'), 11, 3);
             }
         }
     }
 }
<?php

// exit if accessed directly
if (!defined('ABSPATH')) {
    exit;
}
if (!current_user_can(apply_filters('searchwp_settings_cap', 'manage_options'))) {
    die;
}
$searchwp = SWP();
?>

<div class="postbox swp-meta-box swp-default-engine metabox-holder swp-jqueryui">

	<?php 
$the_link = admin_url('index.php?page=searchwp-stats') . '&tab=default';
?>
	<h3 class="hndle"><span><?php 
_e('Default Search Engine', 'searchwp');
?>
</span> <a class="swp-engine-stats" href="<?php 
echo esc_url($the_link);
?>
"><?php 
_e('Statistics', 'searchwp');
?>
 &raquo;</a></h3>

	<div class="inside">

		<p><?php 
 function __construct()
 {
     $this->searchwp = SWP();
 }
Example #6
0
    function plugin_row()
    {
        if (!class_exists('SearchWP')) {
            return;
        }
        $searchwp = SWP();
        if (version_compare($searchwp->version, '2.0.3', '<')) {
            ?>
			<tr class="plugin-update-tr searchwp">
				<td colspan="3" class="plugin-update">
					<div class="update-message">
						<?php 
            _e('SearchWP LIKE Terms requires SearchWP 2.0.3 or greater', 'searchwp');
            ?>
					</div>
				</td>
			</tr>
		<?php 
        }
    }
<?php

if ( ! defined( 'ABSPATH' ) ) {
	die();
}

$parent = SWP();

$parent->define_keys();
$lazy_settings = apply_filters( 'searchwp_lazy_settings', false );

// progress of indexer
$remainingPostsToIndex = searchwp_get_setting( 'remaining', 'stats' );
$progress = searchwp_get_option( 'progress' );
if ( ! $parent->is_using_alternate_indexer() && ( ! is_bool( $remainingPostsToIndex ) || ( is_numeric( $progress ) && $progress > 0 && $progress < 100 ) ) ) {
	$remainingPostsToIndex = absint( $remainingPostsToIndex );
	?>
	<div class="updated settings-error swp-in-progress<?php if ( 0 === $remainingPostsToIndex ) : ?> swp-in-progress-done<?php endif; ?>">
		<div class="swp-progress-wrapper">
			<p class="swp-label"><?php _e( 'Indexing is', 'searchwp' ); ?>
				<span><?php _e( 'almost', 'searchwp' ); ?></span> <?php _e( 'complete', 'searchwp' ); ?>
				<a class="swp-tooltip" href="#swp-tooltip-progress">?</a></p>

			<div class="swp-tooltip-content" id="swp-tooltip-progress">
				<?php _e( 'This process is running in the background. You can leave this page and the index will continue to be built until completion.', 'searchwp' ); ?>
			</div>
			<div class="swp-progress-track">
				<div class="swp-progress-bar"></div>
			</div>
			<p class="description"><?php echo sprintf( __( 'The indexer has been <strong>temporarily scaled back</strong> to reduce server load. This is monitored automatically. <a href="%s">More information &raquo;</a>', 'searchwp' ), 'http://searchwp.com/?p=11818' ); ?></p>
		</div>
 /**
  * Perform various environment checks/initializations on wp_loaded
  *
  * @since 1.8
  */
 function load()
 {
     global $wp_query;
     if (apply_filters('searchwp_debug', false)) {
         $wp_upload_dir = wp_upload_dir();
         $debug = new SearchWPDebug();
         $debug->init($wp_upload_dir['basedir']);
     }
     do_action('searchwp_log', ' ');
     do_action('searchwp_log', '========== INIT ' . $this->pid . ' ' . SEARCHWP_VERSION . ' ==========');
     do_action('searchwp_log', ' ');
     $this->prepare_endpoint();
     // check for upgrade
     new SearchWPUpgrade($this->version);
     // ensure working database environment
     $this->check_database_environment();
     // set the registered post types
     $this->postTypes = array_merge(array('post' => 'post', 'page' => 'page', 'attachment' => 'attachment'), get_post_types(array('exclude_from_search' => false, '_builtin' => false)));
     // devs can customize which post types are indexed, it doesn't make
     // sense to list post types that were excluded (or included (e.g. post types that don't
     // allow filtration of the exclude_from_search arg))
     $this->postTypes = $this->get_indexed_post_types();
     // if the settings were somehow edited directly in the database
     $this->settings = SWP()->validate_settings($this->settings);
     // allow filtration of what SearchWP considers common words (i.e. ignores)
     $this->common = apply_filters('searchwp_common_words', $this->common);
     $this->alternate_indexer = apply_filters('searchwp_alternate_indexer', false);
     // one-stop filter to ensure SearchWP fires
     if ($this->force_run = apply_filters('searchwp_force_run', $this->force_run)) {
         $wp_query->is_search = true;
     }
     $this->check_if_paused();
     $this->set_index_update_triggers();
     do_action('searchwp_load');
     // handle index and/or purge requests
     $this->update_index();
     // reset short circuit check
     $this->indexing = false;
 }
    /**
     * Plugin row output (checks for minimum SearchWP version)
     */
    function plugin_row()
    {
        if (!class_exists('SearchWP')) {
            return;
        }
        $searchwp = SWP();
        if (version_compare($searchwp->version, $this->min_searchwp_version, '<')) {
            ?>
			<tr class="plugin-update-tr searchwp">
				<td colspan="3" class="plugin-update">
					<div class="update-message">
						<?php 
            esc_html_e('SearchWP Term Synonyms requires a newer version of SearchWP', 'searchwptermsyn');
            ?>
					</div>
				</td>
			</tr>
		<?php 
        }
    }
} else {
    $current_user = wp_get_current_user();
    $conflicts_var = '';
    $conflicts = new SearchWP_Conflicts();
    if (!empty($conflicts->search_template_conflicts)) {
        // strip out the full disk path
        $search_template = str_replace(get_theme_root(), '', $conflicts->search_template);
        $conflicts_var = $search_template . ':';
        foreach ($conflicts->search_template_conflicts as $line_number => $the_conflicts) {
            $conflicts_var .= $line_number . ',';
        }
        $conflicts_var = substr($conflicts_var, 0, strlen($conflicts_var) - 1);
        // trim off the trailing comma
    }
    /** @noinspection PhpUndefinedFieldInspection */
    $iframe_url = add_query_arg(array('support' => 1, 'f' => 6, 'dd' => 0, 'dt' => 0, 'license' => SWP()->license, 'email' => urlencode($current_user->user_email), 'url' => urlencode(home_url()), 'env' => defined('WPE_APIKEY') ? 'wpe' : 0, 'conflicts' => urlencode($conflicts_var), 'searchwp_v' => urlencode(get_option('searchwp_version')), 'wp_v' => urlencode(get_bloginfo('version')), 'php_v' => urlencode(PHP_VERSION), 'mysql_v' => urlencode($wpdb->db_version())), 'https://searchwp.com/gfembed/');
    $ticket_create_url = $iframe_url;
    ?>
	<div class="searchwp-ticket-create-wrapper">
		<iframe src="<?php 
    echo esc_url($ticket_create_url);
    ?>
" frameborder="0"></iframe>
	</div>
	<?php 
}
?>
</div>

<hr />
    function plugin_row()
    {
        if (!class_exists('SearchWP')) {
            return;
        }
        $searchwp = SWP();
        if (version_compare($searchwp->version, '1.0.10', '<')) {
            ?>
			<tr class="plugin-update-tr searchwp">
				<td colspan="3" class="plugin-update">
					<div class="update-message">
						<?php 
            esc_html_e('SearchWP bbPress Integration requires SearchWP 1.0.10 or greater', 'searchwp');
            ?>
					</div>
				</td>
			</tr>
		<?php 
        }
    }
    function plugin_row()
    {
        if (!class_exists('SearchWP')) {
            ?>
			<tr class="plugin-update-tr searchwp">
				<td colspan="3" class="plugin-update">
					<div class="update-message">
						<?php 
            _e('SearchWP must be active to use this Extension');
            ?>
					</div>
				</td>
			</tr>
		<?php 
        } else {
            ?>
		<?php 
            $searchwp = SWP();
            ?>
		<?php 
            if (version_compare($searchwp->version, '1.1', '<')) {
                ?>
			<tr class="plugin-update-tr searchwp">
				<td colspan="3" class="plugin-update">
					<div class="update-message">
						<?php 
                _e('SearchWP Polylang Integration requires SearchWP 1.1 or greater', $searchwp->textDomain);
                ?>
					</div>
				</td>
			</tr>
		<?php 
            }
            ?>
	<?php 
        }
    }
 /**
  * Ensure that this engine exists.
  *
  * @since 0.1.0
  *
  * @param string $engine
  *
  * @return bool
  */
 public function validate_engine($engine)
 {
     return SWP()->is_valid_engine($engine);
 }
    echo esc_textarea($export_sources_json);
    ?>
</textarea>
			</div>
			<div class="swp-import-export-sources">
				<h4><?php 
    _e('Search Engines', 'searchwp');
    ?>
</h4>
				<p class="description"><?php 
    _e('Checked search engines will be included in the export', 'searchwp');
    ?>
</p>
				<?php 
    $engine_id = 0;
    foreach (SWP()->settings['engines'] as $searchwp_engine_id => $searchwp_export_source) {
        ?>
					<?php 
        $engine_label = isset($searchwp_export_source['searchwp_engine_label']) ? $searchwp_export_source['searchwp_engine_label'] : __('Default', 'searchwp');
        ?>
					<div class="swp-export-source">
						<input type="checkbox" id="<?php 
        echo esc_attr(strtolower($engine_label));
        ?>
" checked="checked" data-swp-engine-id="<?php 
        echo esc_attr($searchwp_engine_id);
        ?>
" />
						<label for="<?php 
        echo esc_attr(strtolower($engine_label));
        ?>
/**
 * Set a setting in the SearchWP singleton. To reduce database calls this update will take place only in the singleton
 * and made persistent by saving to the database when WordPress shuts down.
 *
 * @param      $setting
 * @param      $value
 * @param bool $group
 *
 * @return bool
 */
function searchwp_set_setting($setting, $value, $group = false)
{
    $searchwp = SWP();
    // validate the request
    $setting = trim($setting);
    if (empty($setting)) {
        return false;
    }
    if (false !== $group) {
        $group = trim($group);
        if (empty($group)) {
            return false;
        }
    }
    // Settings in SearchWP are a bit unique. There are 'configuration' settings and 'indexer' settings. Configuration
    // settings are those that configure the plugin, the search engine config, keyword weights, etc. The indexer settings
    // store various details for the indexer to utilize. Since the indexer runs independently and is constantly updating
    // it's internal settings, we don't want updates to these settings records to ever collide, so we're going to "route"
    // them here based on their name and/or group.
    $indexer_names = array('initial_index_built', 'stats', 'remaining', 'last_activity', 'total', 'done', 'in_progress', 'running', 'paused', 'processing_purge_queue', 'endpoint');
    // check the setting name to see whether we need to retrieve a searchwp setting or an indexer setting
    if (in_array($setting, $indexer_names) || in_array($group, $indexer_names)) {
        // it's an indexer setting
        $indexer_settings = get_option(SEARCHWP_PREFIX . 'indexer');
        // set the setting locally and in the singleton
        if (false !== $group) {
            // make sure the group exists
            if (!isset($indexer_settings[$group])) {
                $indexer_settings[$group] = array();
            }
            if (!isset($searchwp->settings[$group])) {
                $searchwp->settings[$group] = array();
            }
            $indexer_settings[$group][$setting] = $value;
            // database record
            $searchwp->settings[$group][$setting] = $value;
            // singleton
        } else {
            $indexer_settings[$setting] = $value;
            // database record
            $searchwp->settings[$setting] = $value;
            // singleton
        }
        // update the database record
        searchwp_update_option('indexer', $indexer_settings);
    } else {
        // it's a SearchWP configuration
        $searchwp_settings = get_option(SEARCHWP_PREFIX . 'settings');
        // set the setting locally and in the singleton
        if (false !== $group) {
            // make sure the group exists
            if (!isset($searchwp_settings[$group])) {
                $searchwp_settings[$group] = array();
            }
            if (!isset($searchwp->settings[$group])) {
                $searchwp->settings[$group] = array();
            }
            $searchwp_settings[$group][$setting] = $value;
            // database record
            $searchwp->settings[$group][$setting] = $value;
            // singleton
        } else {
            $searchwp_settings[$setting] = $value;
            // database record
            $searchwp->settings[$setting] = $value;
            // singleton
        }
        // update the database record
        searchwp_update_option('settings', $searchwp_settings);
    }
    return true;
}
 /**
  * Legacy post retrieval for WooCommerce <2.6
  *
  * @param $filtered_posts
  *
  * @return array
  */
 function legacy_post_in($filtered_posts)
 {
     global $wp_query;
     if ($this->is_woocommerce_search() && function_exists('SWP') && !isset($_GET['orderby']) && ($query = get_search_query())) {
         $searchwp_engine = 'default';
         $searchwp = SWP();
         $swppg = get_query_var('paged') ? get_query_var('paged') : 1;
         add_filter('searchwp_load_posts', '__return_false');
         add_filter('searchwp_posts_per_page', array($this, 'set_pagination'));
         // force SearchWP to only consider the filtered posts
         if (!empty($filtered_posts)) {
             $this->filtered_posts = $filtered_posts;
             add_filter('searchwp_include', array($this, 'include_filtered_posts'));
         }
         // don't log this search, it's redundant
         add_filter('searchwp_log_search', '__return_false');
         $this->results = $searchwp->search($searchwp_engine, $query, $swppg);
         remove_filter('searchwp_log_search', '__return_false');
         remove_filter('searchwp_load_posts', '__return_false');
         remove_filter('searchwp_posts_per_page', array($this, 'set_pagination'));
         $filtered_posts = array_intersect($this->results, (array) $filtered_posts);
         $filtered_posts = array_unique($filtered_posts);
         // also set our WooCommerce Instance IDs
         WC()->query->unfiltered_product_ids = $this->results;
     }
     return (array) $filtered_posts;
 }
 /**
  * Retrieve search results from SearchWP
  *
  * @since 2.6
  */
 function get_search_results()
 {
     $swp_query = SWP();
     add_filter('searchwp_posts_per_page', array($this, 'get_posts_per_page'));
     if (!$this->load_posts) {
         add_filter('searchwp_load_posts', '__return_false');
     }
     $this->posts = $swp_query->search($this->engine, $this->s, $this->page);
     // store the SQL used to get this results set
     $this->request = $swp_query->get_last_search_sql();
     $this->found_posts = intval($swp_query->foundPosts);
     $this->post_count = count($this->posts);
     $this->max_num_pages = intval($swp_query->maxNumPages);
     $this->posts_weights = $swp_query->results_weights;
     if (empty($this->posts) || 0 == count($this->posts)) {
         $this->found_posts = 0;
         $this->post_count = 0;
         $this->max_num_pages = 0;
         $this->posts_weights = array();
     }
     remove_filter('searchwp_posts_per_page', array($this, 'get_posts_per_page'));
     if (!$this->load_posts) {
         remove_filter('searchwp_load_posts', '__return_false');
     }
 }
    /**
     * Outputs the HTML to manage the license key
     */
    function render_view_license()
    {
        $searchwp = SWP();
        $license = $searchwp->license;
        $status = $searchwp->status;
        ?>
		<div class="searchwp-license-settings-wrapper swp-group">
			<div class="postbox swp-meta-box metabox-holder searchwp-settings-license">
				<h3 class="hndle">
					<span><?php 
        esc_html_e('Manage Your SearchWP License', 'searchwp');
        ?>
						<?php 
        if (false !== $status && 'valid' == $status) {
            ?>
 <b class="active"><?php 
            _e('Active', 'searchwp');
            ?>
</b><?php 
        } else {
            ?>
<b class="inactive"><?php 
            _e('Inactive', 'searchwp');
            ?>
</b><?php 
        }
        ?>
					</span></h3>
				<div class="inside">
					<?php 
        if (false !== $status && 'valid' == $status) {
            ?>
						<p><?php 
            esc_html_e('Your SearchWP license is currently active.', 'searchwp');
            ?>
</p>
					<?php 
        } else {
            ?>
						<p><?php 
            esc_html_e('SearchWP requires an active license to receive automatic upates and support. Enter your license key to activate it.', 'searchwp');
            ?>
</p>
					<?php 
        }
        ?>
					<form method="post" action="options.php">
						<?php 
        settings_fields(SEARCHWP_PREFIX . 'license');
        ?>
						<p>
							<!--suppress HtmlFormInputWithoutLabel -->
							<input id="<?php 
        echo esc_attr(SEARCHWP_PREFIX);
        ?>
license_key" name="<?php 
        echo esc_attr(SEARCHWP_PREFIX);
        ?>
license_key" type="text" class="regular-text" value="<?php 
        echo esc_attr($license);
        ?>
" />
							<?php 
        if (false !== $status && 'valid' == $status) {
            ?>
								<?php 
            wp_nonce_field('searchwp_edd_license_deactivate_nonce', 'searchwp_edd_license_deactivate_nonce');
            ?>
								<input type="submit" class="button-secondary" name="edd_license_deactivate" value="<?php 
            _e('Deactivate', 'searchwp');
            ?>
"/>
							<?php 
        } else {
            wp_nonce_field('searchwp_edd_license_activate_nonce', 'searchwp_edd_license_activate_nonce');
            ?>
								<input type="submit" class="button-secondary" name="edd_license_activate" value="<?php 
            _e('Activate', 'searchwp');
            ?>
"/>
							<?php 
        }
        ?>
						</p>
					</form>
					<?php 
        if (false !== $status && 'valid' == $status) {
            ?>
						<p class="description"><?php 
            echo sprintf(__('Active for another %s', 'searchwp'), $this->get_time_until_expiration());
            ?>
</p>
					<?php 
        } else {
            ?>
						<p class="description"><?php 
            echo sprintf(__('Your license key is available both on your payment receipt and in your <a href="%s">Account</a>', 'searchwp'), 'https://searchwp.com/account/');
            ?>
</p>
					<?php 
        }
        ?>
				</div>
			</div>
		</div>
		<style type="text/css">
			.swp-notices .updated {
				display: none !important;
			}
			.searchwp-settings-license h3 b {
				display:inline-block;
				border-radius:2px;
				color:#fff;
				font-weight:normal;
				padding:0.3em 0.6em 0.4em;
				margin-left:0.7em;
				font-size:0.8em;
				line-height:1;
				position:relative;
				top:-0.1em;
			}
			.searchwp-settings-license h3 b.active {
				background:#75A575;
			}
			.searchwp-settings-license h3 b.inactive {
				background:#C55959;
			}
		</style>
		<?php 
    }
	/**
	 * Retrieve only the term content from the submitted string
	 *
	 * Modified from Sphider by Ando Saabas, http://www.sphider.eu/
	 *
	 * @param string $content The source content, can include markup
	 * @return string The content without markup or character encoding
	 * @since 1.0
	 */
	function clean_content( $content = '' ) {

		$searchwp = SWP();

		if ( is_array( $content ) || is_object( $content ) ) {
			$content = $this->parse_variable_for_terms( $content );
		}

		// allow developers the ability to customize content where necessary (e.g. remove TM symbols)
		$content = apply_filters( 'searchwp_indexer_pre_process_content', $content );

		if ( function_exists( 'mb_convert_encoding' ) ) {
			$content = mb_convert_encoding( $content, 'UTF-8', 'UTF-8' );
		}

		if ( empty( $searchwp->settings['utf8mb4'] ) ) {
			$content = $searchwp->replace_4_byte( $content );
		}

		// we want to extract potentially valuable content from certain HTML attributes
		$accepted_attributes = apply_filters( 'searchwp_indexer_tag_attributes', array(
			'a'     => array( 'title' ),
			'img'   => array( 'alt', 'src', 'longdesc', 'title' ),
			'input' => array( 'placeholder', 'value' ),
		) );

		// parse $content as a DOMDocument and if applicable extract the accepted attribute content
		$attribute_content = array();
		$content = trim( $content );
		if ( ! empty( $accepted_attributes )
		     && ! empty( $content )
		     && is_array( $accepted_attributes )
		     && class_exists( 'DOMDocument' )
		     && function_exists( 'libxml_use_internal_errors' )
		) {
			$dom = new DOMDocument();
			libxml_use_internal_errors( true );
			$dom->loadHTML( $content );
			// loop through our accepted tags
			foreach ( $accepted_attributes as $tag => $attributes ) {
				// grab any $tag matches
				$node_list = $dom->getElementsByTagName( $tag );
				for ( $i = 0; $i < $node_list->length; $i++ ) {
					$node = $node_list->item( $i );
					if ( $node->hasAttributes() ) {
						foreach ( $node->attributes as $attr ) {
							if ( isset( $attr->name ) && in_array( $attr->name, $attributes ) ) {
								$attribute_content[] = sanitize_text_field( $attr->nodeValue );
							}
						}
					}
				}
			}
		}

		// append the attribute content to our main content block
		if ( ! empty( $attribute_content ) ) {
			$content .= ' ' . implode( ' ', $attribute_content );
		}

		// we need front and back spaces so we can perform exact matches when whitelisting
		$content = ' ' . $content . ' ';  // we need front and back spaces so we can perform exact matches when whitelisting

		// extract terms based on whitelist pattern, allowing for approved indexing of terms with punctuation
		$whitelisted_terms = $searchwp->extract_terms_using_pattern_whitelist( $content );

		// when indexing we do not want to remove the matches; we're going to run everything through
		// the regular sanitization so as to open the possibility for better partial matching (especially
		// when taking into consideration the use of LIKE Terms or another extension)

		// there may be times however, that the developer does in fact want matches to be exclusively kept together
		if ( apply_filters( 'searchwp_exclusive_regex_matches', false ) ) {
			// add the buffer so we can whole-word replace
			$content = str_replace( ' ', '  ', $content );

			// remove the matches
			if ( ! empty( $whitelisted_terms ) ) {
				$content = str_ireplace( $whitelisted_terms, ' ', $content );
			}

			// clean up the double space flag we used
			$content = str_replace( '  ', ' ', $content );
		}

		// buffer tags with spaces before removing them
		$content = preg_replace( '/<[\w ]+>/', "\\0 ", $content );
		$content = preg_replace( '/<\/[\w ]+>/', "\\0 ", $content );
		$content = preg_replace( '/&nbsp;/', ' ', $content );

		$content = function_exists( 'mb_strtolower' ) ? mb_strtolower( $content ) : strtolower( $content );

		// <br> tags can be problematic on their own if there's no whitespace surrounding
		// what should be separate lines of text, so we'll manually do that prior to stripping
		$content = str_replace( array( '<br />', '<br/>', '<br>' ), ' ', $content );

		// since we've extracted and appended the attribute content we can strip the tags entirely
		$content = strip_tags( $content );

		$content = stripslashes( $content );

		// remove punctuation
		$punctuation = array( '(', ')', '·', "'", '´', '’', '‘', '”', '“', '„', '—', '–', '×', '…', '€', '\n', '.', ',', '/', '\\', '|', '[', ']', '{', '}', '•', '`' );
		$content = str_replace( $punctuation, ' ', $content );
		$content = preg_replace( '/[[:punct:]]/uiU', ' ', $content );
		$content = preg_replace( '/[[:space:]]/uiU', ' ', $content );

		// append our whitelist
		if ( is_array( $whitelisted_terms ) && ! empty( $whitelisted_terms ) ) {
			$whitelisted_terms = array_map( 'trim', $whitelisted_terms );
			$whitelisted_terms = array_filter( $whitelisted_terms, 'strlen' );
			$content .= ' ' . implode( ' ' , $whitelisted_terms );
		}

		$content = sanitize_text_field( $content );
		$content = trim( $content );

		return $content;
	}
 /**
  * Dynamically generate SQL query based on engine settings and retrieve a weighted, ordered list of posts
  *
  * @return bool|array Post IDs found in the index
  * @since 1.0
  */
 function query_for_post_ids()
 {
     global $wpdb;
     do_action('searchwp_log', 'query_for_post_ids()');
     // check to make sure there are settings for the current engine
     if (!isset($this->settings['engines'][$this->engine]) && is_array($this->settings['engines'][$this->engine])) {
         return false;
     }
     // check to make sure we actually have terms to search
     // TODO: refactor this
     if (empty($this->terms)) {
         // short circuit
         $this->foundPosts = 0;
         $this->maxNumPages = 0;
         $this->postIDs = array();
         return false;
     }
     // pull out our engine-specific settings
     $all_settings = SWP()->validate_settings($this->settings);
     if (!isset($all_settings['engines']) || !isset($all_settings['engines'][$this->engine])) {
         wp_die(__('Engine settings not found', 'searchwp'));
     }
     $this->engineSettings = $all_settings['engines'][$this->engine];
     // stemming is locale-specific so we might need to disable that if it's not applicable
     // DISABLED for now because of back compat e.g. if someone has an outdated German stemmer, stemming would just stop
     //  foreach ( $this->engineSettings as $postType => $postTypeWeights ) {
     //  	if ( isset( $postTypeWeights['enabled'] ) && true == $postTypeWeights['enabled'] ) {
     //  		if ( isset( $postTypeWeights['options']['stem'] ) && ! empty( $postTypeWeights['options']['stem'] ) ) {
     //  			if ( ! SWP()->is_stemming_supported_in_locale() ) {
     //  				$postTypeWeights['options']['stem'] = false;
     //  			}
     //  		}
     //  	}
     //  }
     // allow filtration of settings at runtime
     $this->engineSettings = apply_filters("searchwp_engine_settings_{$this->engine}", $this->engineSettings, $this->terms);
     // check to make sure that all post types in the settings are still in fact registered and active
     // e.g. in case a Custom Post Type was saved in the settings but no longer exists
     $this->validate_post_types();
     // we might need to short circuit for a number of reasons
     if (!$this->any_enabled_post_types()) {
         return false;
     }
     // we're going to exclude entered IDs for the query as a whole
     // need to get these IDs early because if an attributed post ID is excluded we need to omit it from
     // the query entirely
     $this->set_excluded_ids_from_settings();
     // pull any excluded IDs based on taxonomy term
     $this->set_excluded_ids_from_taxonomies();
     // perform our AND logic before getting started
     // e.g. we're going to limit to posts that have all of the search terms
     $this->maybe_do_and_logic();
     $this->exclude_posts_by_weight();
     // allow devs to filter excluded IDs
     $this->excluded = apply_filters('searchwp_exclude', $this->excluded, $this->engine, $this->terms);
     if (is_array($this->excluded)) {
         $this->excluded = array_map('absint', $this->excluded);
     }
     $this->sql_exclude = !empty($this->excluded) ? " AND {$wpdb->prefix}posts.ID NOT IN (" . implode(',', $this->excluded) . ') ' : '';
     // if there's an insane number of posts returned, we're dealing with a site with a lot of similar content
     // so we need to trim out the initial results by relevance before proceeding else we'll have a wicked slow query
     // NOTE: this only applies if titles have weights for all enabled post types, so we must check that first
     $able_to_refine_results = true;
     foreach ($this->engineSettings as $postType => $postTypeWeights) {
         if (isset($postTypeWeights['enabled']) && true == $postTypeWeights['enabled']) {
             $title_weight = isset($postTypeWeights['weights']['title']) ? absint($postTypeWeights['weights']['title']) : 0;
             if (0 == $title_weight) {
                 // at least one title weight is zero so we are NOT ABLE to refine results any
                 // further because the post IDs we find when refining by title will not apply
                 // in the main search query since those title hits are worth nothing
                 $able_to_refine_results = false;
                 break;
             }
         }
     }
     // if the include pool has not been limited, do that
     if (empty($this->included)) {
         $parity = count($this->terms);
         $maxNumAndResults = absint(apply_filters('searchwp_max_and_results', 300));
         if ($parity > 1 && $able_to_refine_results && apply_filters('searchwp_refine_and_results', true) && count($this->relevant_post_ids) > $maxNumAndResults) {
             $this->relevant_post_ids = $this->get_post_ids_via_and_in_title();
         }
         // make sure we've got an array of unique integers
         $this->relevant_post_ids = array_map('absint', array_unique($this->relevant_post_ids));
     } else {
         $this->relevant_post_ids = $this->included;
     }
     // allow devs to filter included post IDs
     add_filter('searchwp_force_wp_query', '__return_true');
     $this->included = apply_filters('searchwp_include', $this->relevant_post_ids, $this->engine, $this->terms);
     remove_filter('searchwp_force_wp_query', '__return_true');
     // allow devs to force AND logic all the time, no matter what (if there was more than one search term)
     $forceAnd = count($this->terms) > 1 && apply_filters('searchwp_and_logic_only', false) ? true : false;
     // if it was totally empty and AND logic is forced, we'll hit a SQL error, so populate it with an impossible ID
     if (empty($this->included) && $forceAnd) {
         $this->included = array(0);
     }
     if (is_array($this->included)) {
         $this->included = array_map('absint', $this->included);
     }
     $this->sql_include = is_array($this->included) && !empty($this->included) || $forceAnd ? " AND {$wpdb->prefix}posts.ID IN (" . implode(',', $this->included) . ') ' : '';
     /**
      * Build the search query
      */
     $this->query_open();
     // allow for injection into main SELECT
     $select_inject = trim((string) apply_filters('searchwp_query_select_inject', ''));
     if (!empty($select_inject)) {
         // we're automatically going to append the comma, so if it was returned we can kill it
         if (',' == substr($select_inject, -1)) {
             $select_inject = substr($select_inject, 0, strlen($select_inject) - 1);
         }
         $this->sql .= ' ' . $select_inject . ' , ';
     }
     $this->query_sum_post_type_weights();
     $this->query_sum_final_weight();
     // allow for pre-algorithm join
     $this->sql = ' ' . (string) apply_filters('searchwp_query_main_join', $this->sql, $this->engine) . ' ';
     // loop through each submitted term
     $termCounter = 1;
     foreach ($this->terms as $term) {
         $this->query_open_term();
         // build our post type queries
         foreach ($this->engineSettings as $postType => $postTypeWeights) {
             if (isset($postTypeWeights['enabled']) && true == $postTypeWeights['enabled']) {
                 // TODO: store our post format clause and integrate
                 // TODO: store our post status clause and integrate
                 // prep the term
                 $prepped_term = $this->prep_term($term, $postTypeWeights);
                 $term = $prepped_term['term'];
                 $term_or_stem = $prepped_term['term_or_stem'];
                 $original_prepped_term = $prepped_term['original_prepped_term'];
                 $this->cache_term_final($term);
                 // build our final term WHERE
                 if (!in_array($term_or_stem, array('term', 'stem'))) {
                     wp_die('Invalid request', 'searchwp');
                 }
                 $this->sql_term_where = " {$this->db_prefix}terms." . $term_or_stem . ' IN (' . implode(',', $term) . ')';
                 /** @noinspection PhpUnusedLocalVariableInspection */
                 $last_term = $term;
                 // if it's an attachment we need to force 'inherit'
                 $post_statuses = $postType == 'attachment' ? array('inherit') : $this->post_statuses;
                 if (is_array($post_statuses)) {
                     foreach ($post_statuses as $key => $val) {
                         $post_statuses[$key] = $wpdb->prepare('%s', $val);
                     }
                 }
                 $this->sql_status = "AND {$wpdb->prefix}posts.post_status IN ( " . implode(',', $post_statuses) . ' ) ';
                 // determine whether we need to limit to a mime type
                 if (isset($postTypeWeights['options']['mimes'])) {
                     // stored as an array of integers that correlate to mime type groups
                     $mimes = explode(',', $postTypeWeights['options']['mimes']);
                     $mimes = array_map('absint', $mimes);
                     $this->query_limit_by_mimes($mimes);
                 }
                 // reset back to our original term
                 $term = $original_prepped_term;
                 // we need to use absint because if a weight was set to -1 for exclusion, it was already forcefully excluded
                 $titleWeight = isset($postTypeWeights['weights']['title']) ? absint($postTypeWeights['weights']['title']) : 0;
                 $slugWeight = isset($postTypeWeights['weights']['slug']) ? absint($postTypeWeights['weights']['slug']) : 0;
                 $contentWeight = isset($postTypeWeights['weights']['content']) ? absint($postTypeWeights['weights']['content']) : 0;
                 $excerptWeight = isset($postTypeWeights['weights']['excerpt']) ? absint($postTypeWeights['weights']['excerpt']) : 0;
                 if (apply_filters('searchwp_index_comments', true)) {
                     $commentWeight = isset($postTypeWeights['weights']['comment']) ? absint($postTypeWeights['weights']['comment']) : 0;
                 } else {
                     $commentWeight = 0;
                 }
                 // build the SQL to accommodate Custom Fields
                 $custom_field_weights = isset($postTypeWeights['weights']['cf']) ? $postTypeWeights['weights']['cf'] : 0;
                 $coalesceCustomFields = $this->query_coalesce_custom_fields($custom_field_weights);
                 // build the SQL to accommodate Taxonomies
                 $taxonomy_weights = isset($postTypeWeights['weights']['tax']) ? $postTypeWeights['weights']['tax'] : 0;
                 $coalesceTaxonomies = $this->query_coalesce_taxonomies($taxonomy_weights);
                 // allow additional tables to be joined
                 $this->sql_join = apply_filters('searchwp_query_join', '', $postType, $this->engine);
                 if (!is_string($this->sql_join)) {
                     $this->sql_join = '';
                 }
                 // allow additional conditions
                 $this->sql_conditions = apply_filters('searchwp_query_conditions', '', $postType, $this->engine);
                 if (!is_string($this->sql_conditions)) {
                     $this->sql_conditions = '';
                 }
                 // if we're dealing with attributed weight we need to make sure that the attribution target was not excluded
                 $excludedByAttribution = false;
                 $attributedTo = false;
                 if (isset($postTypeWeights['options']['attribute_to']) && !empty($postTypeWeights['options']['attribute_to'])) {
                     $postColumn = 'ID';
                     $attributedTo = absint($postTypeWeights['options']['attribute_to']);
                     if (in_array($attributedTo, $this->excluded)) {
                         $excludedByAttribution = true;
                     }
                 } else {
                     // if it's an attachment and we want to attribute to the parent, we need to set that here
                     $postColumn = isset($postTypeWeights['options']['parent']) ? 'post_parent' : 'ID';
                 }
                 // open up the post type subquery if not excluded by attribution
                 if (!$excludedByAttribution) {
                     $post_type_params = array('post_type' => $postType, 'post_column' => $postColumn, 'title_weight' => $titleWeight, 'slug_weight' => $slugWeight, 'content_weight' => $contentWeight, 'comment_weight' => $commentWeight, 'excerpt_weight' => $excerptWeight, 'custom_fields' => isset($coalesceCustomFields) ? $coalesceCustomFields : '', 'taxonomies' => isset($coalesceTaxonomies) ? $coalesceTaxonomies : '', 'attributed_to' => $attributedTo);
                     $this->query_post_type_open($post_type_params);
                     // handle custom field weights
                     if (isset($postTypeWeights['weights']['cf']) && is_array($postTypeWeights['weights']['cf']) && !empty($postTypeWeights['weights']['cf'])) {
                         $this->query_post_type_custom_field_weights($postType, $postTypeWeights['weights']['cf']);
                     }
                     // handle taxonomy weights
                     if (isset($postTypeWeights['weights']['tax']) && is_array($postTypeWeights['weights']['tax']) && !empty($postTypeWeights['weights']['tax'])) {
                         $this->query_post_type_taxonomy_weights($postType, $postTypeWeights['weights']['tax']);
                     }
                     // close out the per-post type sub-query
                     $attribute_to = isset($postTypeWeights['options']['attribute_to']) ? absint($postTypeWeights['options']['attribute_to']) : false;
                     $this->query_post_type_close($postType, $attribute_to);
                 }
             }
         }
         $this->sql .= " LEFT JOIN {$this->db_prefix}index ON {$this->db_prefix}index.post_id = {$wpdb->prefix}posts.ID ";
         $this->sql .= " LEFT JOIN {$this->db_prefix}terms ON {$this->db_prefix}terms.id = {$this->db_prefix}index.term ";
         // make sure we're only getting posts with actual weight
         $this->query_limit_post_type_to_weight();
         $this->sql .= $this->query_limit_pool_by_stem();
         $this->sql .= $this->post_status_limiter_sql($this->engineSettings);
         $this->sql .= ' GROUP BY post_id';
         $this->sql .= " ) AS term{$termCounter} ON term{$termCounter}.post_id = {$wpdb->prefix}posts.ID ";
         $termCounter++;
     }
     /**
      * END LOOP THROUGH EACH SUBMITTED TERM
      */
     // make sure we're only getting posts with actual weight
     $this->query_limit_to_weight();
     $this->sql .= $this->post_status_limiter_sql($this->engineSettings);
     $modifier = $this->postsPer < 1 ? 1 : $this->postsPer;
     // if posts_per_page is -1 there's no offset
     $start = !empty($this->offset) ? $this->offset : intval(($this->page - 1) * $modifier);
     $total = intval($this->postsPer);
     $order = $this->order;
     // accommodate a custom offset
     $start = absint(apply_filters('searchwp_query_limit_start', $start, $this->page, $this->engine));
     $total = absint(apply_filters('searchwp_query_limit_total', $total, $this->page, $this->engine));
     $extraWhere = apply_filters('searchwp_where', '', $this->engine);
     $this->sql .= ' ' . $extraWhere . ' ';
     // allow developers to order by date
     $orderByDate = apply_filters('searchwp_return_orderby_date', false, $this->engine);
     $finalOrderBySQL = $orderByDate ? " ORDER BY post_date {$order}, finalweight {$order} " : " ORDER BY finalweight {$order}, post_date DESC ";
     // allow developers to return completely random results that meet the minumum weight
     if (apply_filters('searchwp_return_orderby_random', false, $this->engine)) {
         $finalOrderBySQL = ' ORDER BY RAND() ';
     }
     // allow for arbitrary ORDER BY filtration
     $finalOrderBySQL = apply_filters('searchwp_query_orderby', $finalOrderBySQL, $this->engine);
     // make sure we limit the overall wp_posts pool to what was returned in the subqueries
     if ($forceAnd) {
         for ($i = 1; $i <= count($this->terms); $i++) {
             $this->sql .= " AND {$wpdb->prefix}posts.ID IN (term" . $i . '.post_id) ';
         }
     } else {
         $end_cap_limiter = '';
         for ($i = 1; $i <= count($this->terms); $i++) {
             $end_cap_limiter .= 'term' . $i . '.post_id,';
         }
         $this->sql .= " AND {$wpdb->prefix}posts.ID IN (" . substr($end_cap_limiter, 0, strlen($end_cap_limiter) - 1) . ') ';
     }
     // also limit the wp_posts pool taking into consideration exclusions
     $this->sql .= $this->sql_exclude;
     // group the results
     $this->sql .= "\n            GROUP BY {$wpdb->prefix}posts.ID\n            {$finalOrderBySQL}\n        ";
     if ($this->postsPer > 0) {
         $this->sql .= "LIMIT {$start}, {$total}";
     }
     $this->sql = str_replace("\n", ' ', $this->sql);
     $this->sql = str_replace("\t", ' ', $this->sql);
     // allow BIG_SELECTS
     $bigSelects = apply_filters('searchwp_big_selects', false);
     if ($bigSelects) {
         $wpdb->query('SET SQL_BIG_SELECTS=1');
     }
     // retrieve all results and associated weights (SQL was prepared throughout generation)
     $searchwp_query_results = $wpdb->get_results($this->sql);
     // if there was in fact a SQL_BIG_SELECTS error let's grab it and try the query again
     if (isset($wpdb->last_error) && false !== strpos($wpdb->last_error, 'SQL_BIG_SELECTS') && current_user_can(apply_filters('searchwp_settings_cap', 'manage_options'))) {
         do_action('searchwp_log', "!!! SQL_BIG_SELECTS error detected, please add_filter( 'searchwp_big_selects', '__return_true' );");
         // show an entry in the admin bar if it's visible
         if (is_admin_bar_showing()) {
             add_action('wp_footer', array($this, 'admin_bar_sql_big_selects_notice_assets'));
             add_action('wp_before_admin_bar_render', array($this, 'admin_bar_sql_big_selects_notice'), 999);
         } else {
             // TODO: the query failed, so no results are showing, we can't filter titles or content, so we need to do something
         }
     }
     // format the results
     $postIDs = array();
     // going to store all of the returned post IDs
     $this->results_weights = array();
     // store all of the specific weights
     if (!empty($searchwp_query_results)) {
         foreach ($searchwp_query_results as $searchwp_query_result) {
             // store the weights for this post
             $weights = array('post_id' => null, 'weight' => null, 'post_types' => array());
             // the results returned are just the table results from the query, let's format them a bit
             foreach ($searchwp_query_result as $searchwp_query_result_key => $searchwp_query_result_value) {
                 switch ($searchwp_query_result_key) {
                     case 'post_id':
                         $postIDs[] = absint($searchwp_query_result->post_id);
                         $weights['post_id'] = absint($searchwp_query_result->post_id);
                         break;
                     case 'finalweight':
                         $weights['weight'] = absint($searchwp_query_result_value);
                         break;
                     default:
                         $weight_key = str_replace(array('final', 'weight'), '', $searchwp_query_result_key);
                         $weights['post_types'][$weight_key] = absint($searchwp_query_result_value);
                         break;
                 }
             }
             $this->results_weights[$searchwp_query_result->post_id] = $weights;
         }
     }
     do_action('searchwp_log', 'Search results: ' . var_export($postIDs, true));
     // retrieve how many total posts were found without the limit
     $this->foundPosts = (int) $wpdb->get_var(apply_filters_ref_array('found_posts_query', array('SELECT FOUND_ROWS()', &$wpdb)));
     // store an accurate max_num_pages for $wp_query
     $this->maxNumPages = $this->postsPer < 1 ? 1 : ceil($this->foundPosts / $this->postsPer);
     // store our post IDs
     $this->postIDs = $postIDs;
     return true;
 }
 /**
  * Outputs the settings page HTML (in place to (hopefully) get around aggressive page caching in the WP admin)
  *
  * @since 2.3
  */
 function view_settings()
 {
     $parent = SWP();
     $parent->define_keys();
     $parent->get_indexer_communication_result();
     /** @noinspection PhpIncludeInspection */
     include $parent->dir . '/admin/settings.php';
 }
function searchwp_generate_settings($engines)
{
    $searchwp = SWP();
    // grab this early because they're going to be nested
    $dismissed_filter_nags = searchwp_get_option('dismissed');
    $dismissed_filter_nags = isset($dismissed_filter_nags['filter_conflicts']) ? $dismissed_filter_nags['filter_conflicts'] : array();
    $in_process = searchwp_get_option('in_process');
    $in_process = is_array($in_process) ? $in_process : null;
    // reformat all of the saved settings
    $new_settings = array('engines' => $engines, 'activated' => (bool) searchwp_get_option('activated'), 'dismissed' => array('filter_conflicts' => $dismissed_filter_nags, 'nags' => array()), 'notices' => array(), 'valid_db_environment' => (bool) searchwp_get_option('valid_db_environment'), 'ignored_queries' => searchwp_get_option('ignored_queries'), 'remote' => searchwp_get_option('remote'), 'remote_meta' => searchwp_get_option('remote_meta'), 'nuke_on_delete' => searchwp_get_option('nuke_on_delete'));
    // break out settings specific to the indexer since that runs independently
    $indexer_settings = array('initial_index_built' => (bool) searchwp_get_option('initial'), 'stats' => array('done' => (int) searchwp_get_option('done'), 'in_process' => $in_process, 'remaining' => (int) searchwp_get_option('remaining'), 'total' => (int) searchwp_get_option('total'), 'last_activity' => (int) searchwp_get_option('last_activity')), 'running' => (bool) searchwp_get_option('running'), 'paused' => searchwp_get_option('paused'), 'processing_purge_queue' => searchwp_get_option('processingPurgeQueue'));
    // set the nags
    if (searchwp_get_option('indexer_nag')) {
        $new_settings['dismissed']['nags'][] = 'indexer';
    }
    if (searchwp_get_option('license_nag')) {
        $new_settings['dismissed']['nags'][] = 'license';
    }
    if (searchwp_get_option('mysql_version_nag')) {
        $new_settings['dismissed']['nags'][] = 'mysql_version';
    }
    // set the notices
    if (searchwp_get_option('initial_notified')) {
        $new_settings['notices'][] = 'initial';
    }
    // save the new options
    searchwp_add_option('settings', $new_settings);
    searchwp_add_option('settings_backup', array());
    searchwp_add_option('indexer', $indexer_settings);
    searchwp_add_option('purge_queue', searchwp_get_option('purgeQueue'));
    // force our new settings in place
    $searchwp->settings = $new_settings;
    $searchwp->settings_updated = true;
}
	/**
	 * Callback if user chose to import settings
	 */
	function maybe_import_settings() {
		if ( isset( $_POST['searchwp_action'] )
		     && 'import_engine_config' === $_POST['searchwp_action']
		     && isset( $_REQUEST['_wpnonce'] )
		     && wp_verify_nonce( $_REQUEST['_wpnonce'], 'searchwp_import_engine_config' )
		     && isset( $_REQUEST['searchwp_import_source'] )
		) {
			$settings_to_import = stripslashes( $_REQUEST['searchwp_import_source'] );
			SWP()->import_settings( $settings_to_import );
			?>
			<div class="updated">
				<p><?php _e( 'Settings imported', 'searchwp' ); ?></p>
			</div>
		<?php
		}
	}
/**
 * Echoes the markup for the search engine settings UI
 *
 * @param string $engine The engine name
 * @return bool
 * @since 1.0
 */
function searchwp_engine_settings_template($engine = 'default')
{
    $searchwp = SWP();
    $settings = $searchwp->settings;
    $engine = sanitize_key($engine);
    if ('default' != $engine && is_array($settings) && !array_key_exists('engines', $settings)) {
        if (!is_array($settings['engines']) || !array_key_exists($engine, $settings['engines'])) {
            return false;
        }
    }
    $engineSettings = isset($settings['engines']) && isset($settings['engines'][$engine]) ? $settings['engines'][$engine] : false;
    // retrieve list of all post types
    $post_types = array_merge(array('post' => 'post', 'page' => 'page', 'attachment' => 'attachment'), get_post_types(array('exclude_from_search' => false, '_builtin' => false)));
    // devs can customize which post types are indexed, it doesn't make
    // sense to list post types that were excluded (or included (e.g. post types that don't
    // allow filtration of the exclude_from_search arg))
    $indexed_post_types = apply_filters('searchwp_indexed_post_types', $searchwp->postTypes);
    if (is_array($indexed_post_types)) {
        $indexed_post_types = array_merge($post_types, $indexed_post_types);
        $indexed_post_types = array_unique($indexed_post_types);
    }
    if (is_array($indexed_post_types)) {
        $post_types = $indexed_post_types;
    }
    if ('swpengine' == $engine) {
        $engine = '{{ swp.engine }}';
    }
    ?>

<div class="swp-tabbable swp-group">
	<ul class="swp-nav swp-tabs">
		<?php 
    foreach ($post_types as $post_type) {
        $post_type = get_post_type_object($post_type);
        ?>
			<?php 
        if ('attachment' != $post_type->name) {
            ?>
				<?php 
            $engine = esc_attr($engine);
            $post_type->name = esc_attr($post_type->name);
            ?>
				<li data-swp-engine="swp-engine-<?php 
            echo esc_attr($engine);
            ?>
-<?php 
            echo esc_attr($post_type->name);
            ?>
" class="">
					<span>
						<?php 
            $enabled = !empty($engineSettings[$post_type->name]['enabled']);
            ?>
						<input type="checkbox" name="<?php 
            echo esc_attr(SEARCHWP_PREFIX);
            ?>
settings[engines][<?php 
            echo esc_attr($engine);
            ?>
][<?php 
            echo esc_attr($post_type->name);
            ?>
][enabled]" id="swp_engine_<?php 
            echo esc_attr($engine);
            ?>
_<?php 
            echo esc_attr($post_type->name);
            ?>
" value="1" <?php 
            checked($enabled);
            ?>
/>
						<label for="swp_engine_<?php 
            echo esc_attr($engine);
            ?>
_<?php 
            echo esc_attr($post_type->name);
            ?>
" title="<?php 
            echo esc_attr($post_type->labels->name);
            ?>
"><?php 
            echo esc_html($post_type->labels->name);
            ?>
</label>
					</span>
				</li>
			<?php 
        }
        ?>
		<?php 
    }
    ?>
		<li data-swp-engine="swp-engine-<?php 
    echo esc_attr($engine);
    ?>
-attachment" class="">
			<span>
				<?php 
    $enabled = !empty($engineSettings['attachment']['enabled']);
    ?>
				<!--suppress HtmlFormInputWithoutLabel -->
				<input type="checkbox" name="<?php 
    echo esc_attr(SEARCHWP_PREFIX);
    ?>
settings[engines][<?php 
    echo esc_attr($engine);
    ?>
][attachment][enabled]" id="swp_engine_<?php 
    echo esc_attr($engine);
    ?>
_attachment" value="1" <?php 
    checked($enabled);
    ?>
/>
				<label for="swp_engine_<?php 
    echo esc_attr($engine);
    ?>
_posts"><?php 
    _e('Media', 'searchwp');
    ?>
</label>
			</span>
		</li>
	</ul>
	<div class="swp-tab-content">
		<?php 
    foreach ($post_types as $post_type) {
        $post_type = get_post_type_object($post_type);
        ?>
			<?php 
        $engine = esc_attr($engine);
        $post_type->name = esc_attr($post_type->name);
        ?>
			<div class="swp-engine swp-engine-<?php 
        echo esc_attr($engine);
        ?>
 swp-group swp-tab-pane" id="swp-engine-<?php 
        echo esc_attr($engine);
        ?>
-<?php 
        echo esc_attr($post_type->name);
        ?>
">
				<h4 class="swp-post-type-heading"><?php 
        echo esc_html($post_type->label);
        ?>
</h4>
				<?php 
        $weights = !empty($engineSettings[$post_type->name]['weights']) ? $engineSettings[$post_type->name]['weights'] : array();
        ?>
				<div class="swp-tooltip-content" id="swp-tooltip-weights-<?php 
        echo esc_attr($engine);
        ?>
_<?php 
        echo esc_attr($post_type->name);
        ?>
">
					<?php 
        _e('These values add weight to results.<br /><br />A weight of 1 is neutral<br />Between 0 &amp; 1 lowers result weight<br />Over 1 increases result weight<br />Zero omits the result<br /><span class="searchwp-weight-warning">-1 excludes matches</span>', 'searchwp');
        ?>
				</div>
				<!-- <p class="description" style="padding-bottom:10px;"><?php 
        _e('Applicable entries', 'searchwp');
        ?>
: <?php 
        $count_posts = wp_count_posts($post_type->name);
        echo 'attachment' != $post_type->name ? absint($count_posts->publish) : absint($count_posts->inherit);
        ?>
</p> -->
				<div class="swp-engine-weights">
					<table>
						<colgroup>
							<col class="swp-col-content-type" />
							<col class="swp-col-content-weight" />
						</colgroup>
						<thead>
							<tr>
								<th><?php 
        _e('Content Type', 'searchwp');
        ?>
</th>
								<th><?php 
        _e('Weight', 'searchwp');
        ?>
 <a class="swp-tooltip" href="#swp-tooltip-weights-<?php 
        echo esc_attr($engine);
        ?>
_<?php 
        echo esc_attr($post_type->name);
        ?>
">?</a></th>
							</tr>
						</thead>
						<tbody>

							<?php 
        if (post_type_supports($post_type->name, 'title')) {
            ?>
								<tr>
									<td><label for="swp_engine_<?php 
            echo esc_attr($engine);
            ?>
_<?php 
            echo esc_attr($post_type->name);
            ?>
_weights_title"><?php 
            _e('Title', 'searchwp');
            ?>
</label></td>
									<td><input type="number" min="-1" step="0.1" class="small-text" name="<?php 
            echo esc_attr(SEARCHWP_PREFIX);
            ?>
settings[engines][<?php 
            echo esc_attr($engine);
            ?>
][<?php 
            echo esc_attr($post_type->name);
            ?>
][weights][title]" id="swp_engine_<?php 
            echo esc_attr($engine);
            ?>
_<?php 
            echo esc_attr($post_type->name);
            ?>
_weights_title" value="<?php 
            echo searchwp_get_engine_weight($weights, 'title');
            ?>
" /></td>
								</tr>
							<?php 
        }
        ?>
							<?php 
        if (post_type_supports($post_type->name, 'editor') || 'attachment' == $post_type->name) {
            ?>
								<tr>
									<td><label for="swp_engine_<?php 
            echo esc_attr($engine);
            ?>
_<?php 
            echo esc_attr($post_type->name);
            ?>
_weights_content"><?php 
            if ('attachment' != $post_type->name) {
                _e('Content', 'searchwp');
            } else {
                _e('Description', 'searchwp');
            }
            ?>
</label></td>
									<td><input type="number" min="-1" step="0.1" class="small-text" name="<?php 
            echo esc_attr(SEARCHWP_PREFIX);
            ?>
settings[engines][<?php 
            echo esc_attr($engine);
            ?>
][<?php 
            echo esc_attr($post_type->name);
            ?>
][weights][content]" id="swp_engine_<?php 
            echo esc_attr($engine);
            ?>
_<?php 
            echo esc_attr($post_type->name);
            ?>
_weights_content" value="<?php 
            echo searchwp_get_engine_weight($weights, 'content');
            ?>
" /></td>
								</tr>
							<?php 
        }
        ?>
							<?php 
        if ('page' == $post_type->name || $post_type->publicly_queryable) {
            ?>
								<tr>
									<td><label for="swp_engine_<?php 
            echo esc_attr($engine);
            ?>
_<?php 
            echo esc_attr($post_type->name);
            ?>
_weights_slug"><?php 
            _e('Slug', 'searchwp');
            ?>
</label></td>
									<td><input type="number" min="-1" step="0.1" class="small-text" name="<?php 
            echo esc_attr(SEARCHWP_PREFIX);
            ?>
settings[engines][<?php 
            echo esc_attr($engine);
            ?>
][<?php 
            echo esc_attr($post_type->name);
            ?>
][weights][slug]" id="swp_engine_<?php 
            echo esc_attr($engine);
            ?>
_<?php 
            echo esc_attr($post_type->name);
            ?>
_weights_slug" value="<?php 
            echo searchwp_get_engine_weight($weights, 'slug');
            ?>
" /></td>
								</tr>
							<?php 
        }
        ?>
							<?php 
        $taxonomies = apply_filters('searchwp_lightweight_settings', false) ? array() : get_object_taxonomies($post_type->name);
        if (is_array($taxonomies) && count($taxonomies)) {
            foreach ($taxonomies as $taxonomy) {
                if ('post_format' != $taxonomy) {
                    // we don't want Post Formats here
                    $taxonomy = get_taxonomy($taxonomy);
                    $tax_label = !empty($taxonomy->labels->name) ? $taxonomy->labels->name : $taxonomy->name;
                    ?>
										<tr>
											<td><label
													for="swp_engine_<?php 
                    echo esc_attr($engine);
                    ?>
_<?php 
                    echo esc_attr($post_type->name);
                    ?>
_weights_tax_<?php 
                    echo esc_attr($taxonomy->name);
                    ?>
"><?php 
                    echo esc_html($tax_label);
                    ?>
</label>
											</td>
											<td><input type="number" min="-1" step="0.1" class="small-text"
											           name="<?php 
                    echo esc_attr(SEARCHWP_PREFIX);
                    ?>
settings[engines][<?php 
                    echo esc_attr($engine);
                    ?>
][<?php 
                    echo esc_attr($post_type->name);
                    ?>
][weights][tax][<?php 
                    echo esc_attr($taxonomy->name);
                    ?>
]"
											           id="swp_engine_<?php 
                    echo esc_attr($engine);
                    ?>
_<?php 
                    echo esc_attr($post_type->name);
                    ?>
_weights_tax_<?php 
                    echo esc_attr($taxonomy->name);
                    ?>
"
											           value="<?php 
                    echo searchwp_get_engine_weight($weights, 'tax', $taxonomy->name);
                    ?>
"/>
											</td>
										</tr>
									<?php 
                }
            }
        }
        ?>
							<?php 
        if (post_type_supports($post_type->name, 'excerpt') || 'attachment' == $post_type->name) {
            ?>
								<tr>
									<td><label for="swp_engine_<?php 
            echo esc_attr($engine);
            ?>
_<?php 
            echo esc_attr($post_type->name);
            ?>
_weights_excerpt"><?php 
            if ('attachment' != $post_type->name) {
                _e('Excerpt', 'searchwp');
            } else {
                _e('Caption', 'searchwp');
            }
            ?>
</label></td>
									<td><input type="number" min="-1" step="0.1" class="small-text" name="<?php 
            echo esc_attr(SEARCHWP_PREFIX);
            ?>
settings[engines][<?php 
            echo esc_attr($engine);
            ?>
][<?php 
            echo esc_attr($post_type->name);
            ?>
][weights][excerpt]" id="swp_engine_<?php 
            echo esc_attr($engine);
            ?>
_<?php 
            echo esc_attr($post_type->name);
            ?>
_weights_excerpt" value="<?php 
            echo searchwp_get_engine_weight($weights, 'excerpt');
            ?>
" /></td>
								</tr>
							<?php 
        }
        ?>
							<?php 
        if (post_type_supports($post_type->name, 'comments') && 'attachment' != $post_type->name) {
            ?>
								<?php 
            if (apply_filters('searchwp_index_comments', true)) {
                ?>
									<tr>
										<td><label for="swp_engine_<?php 
                echo esc_attr($engine);
                ?>
_<?php 
                echo esc_attr($post_type->name);
                ?>
_weights_comment"><?php 
                _e('Comments', 'searchwp');
                ?>
</label></td>
										<td><input type="number" min="-1" step="0.1" class="small-text" name="<?php 
                echo esc_attr(SEARCHWP_PREFIX);
                ?>
settings[engines][<?php 
                echo esc_attr($engine);
                ?>
][<?php 
                echo esc_attr($post_type->name);
                ?>
][weights][comment]" id="swp_engine_<?php 
                echo esc_attr($engine);
                ?>
_<?php 
                echo esc_attr($post_type->name);
                ?>
_weights_comment" value="<?php 
                echo searchwp_get_engine_weight($weights, 'comment');
                ?>
" /></td>
									</tr>
								<?php 
            }
            ?>
							<?php 
        }
        ?>

							<?php 
        if ('attachment' == $post_type->name) {
            ?>
								<?php 
            // check to see if the PDF weight has already been stored
            // if not, use default content weight
            $pdfweight = searchwp_get_engine_weight($weights, 'content');
            if (isset($engineSettings[$post_type->name]['weights']['cf']) && is_array($engineSettings[$post_type->name]['weights']['cf']) && !empty($engineSettings[$post_type->name]['weights']['cf'])) {
                $cfWeights = $engineSettings[$post_type->name]['weights']['cf'];
                foreach ($cfWeights as $cfFlag => $cfWeight) {
                    if ($cfWeight['metakey'] == SEARCHWP_PREFIX . 'content') {
                        $pdfweight = floatval($cfWeight['weight']);
                        break;
                    }
                }
            }
            $arrayFlag = str_replace('.', '', uniqid('swpp', true));
            ?>
								<tr class="swp-custom-field">
									<td class="swp-custom-field-select">
										<label for="swp_engine_<?php 
            echo esc_attr($engine);
            ?>
_<?php 
            echo esc_attr($post_type->name);
            ?>
_<?php 
            echo $arrayFlag;
            ?>
_weight"><?php 
            _e('Document (PDF) content (when applicable)', 'searchwp');
            ?>
</label>
									</td>
									<td>
										<input type="hidden" style="display:none;" name="<?php 
            echo esc_attr(SEARCHWP_PREFIX);
            ?>
settings[engines][<?php 
            echo esc_attr($engine);
            ?>
][<?php 
            echo esc_attr($post_type->name);
            ?>
][weights][cf][<?php 
            echo esc_attr($arrayFlag);
            ?>
][metakey]" value="<?php 
            echo esc_attr(SEARCHWP_PREFIX);
            ?>
content" />
										<input type="number" min="-1" step="0.1" class="small-text" name="<?php 
            echo esc_attr(SEARCHWP_PREFIX);
            ?>
settings[engines][<?php 
            echo esc_attr($engine);
            ?>
][<?php 
            echo esc_attr($post_type->name);
            ?>
][weights][cf][<?php 
            echo esc_attr($arrayFlag);
            ?>
][weight]" id="swp_engine_<?php 
            echo esc_attr($engine);
            ?>
_<?php 
            echo esc_attr($post_type->name);
            ?>
_<?php 
            echo esc_attr($arrayFlag);
            ?>
_weight" value="<?php 
            echo esc_attr($pdfweight);
            ?>
" />
									</td>
								</tr>
								<?php 
            // check to see if the PDF weight has already been stored
            // if not, use default content weight
            $pdf_meta_weight = searchwp_get_engine_weight($weights, 'content');
            if (isset($engineSettings[$post_type->name]['weights']['cf']) && is_array($engineSettings[$post_type->name]['weights']['cf']) && !empty($engineSettings[$post_type->name]['weights']['cf'])) {
                $cfWeights = $engineSettings[$post_type->name]['weights']['cf'];
                foreach ($cfWeights as $cfFlag => $cfWeight) {
                    if ($cfWeight['metakey'] == SEARCHWP_PREFIX . 'pdf_metadata') {
                        $pdf_meta_weight = floatval($cfWeight['weight']);
                        break;
                    }
                }
            }
            $arrayFlag = str_replace('.', '', uniqid('swpp', true));
            ?>
								<tr class="swp-custom-field">
									<td class="swp-custom-field-select">
										<label for="swp_engine_<?php 
            echo esc_attr($engine);
            ?>
_<?php 
            echo esc_attr($post_type->name);
            ?>
_<?php 
            echo esc_attr($arrayFlag);
            ?>
_weight"><?php 
            _e('PDF metadata (when applicable)', 'searchwp');
            ?>
</label>
									</td>
									<td>
										<input type="hidden" style="display:none;" name="<?php 
            echo esc_attr(SEARCHWP_PREFIX);
            ?>
settings[engines][<?php 
            echo esc_attr($engine);
            ?>
][<?php 
            echo esc_attr($post_type->name);
            ?>
][weights][cf][<?php 
            echo esc_attr($arrayFlag);
            ?>
][metakey]" value="<?php 
            echo esc_attr(SEARCHWP_PREFIX);
            ?>
pdf_metadata" />
										<input type="number" min="-1" step="0.1" class="small-text" name="<?php 
            echo esc_attr(SEARCHWP_PREFIX);
            ?>
settings[engines][<?php 
            echo esc_attr($engine);
            ?>
][<?php 
            echo esc_attr($post_type->name);
            ?>
][weights][cf][<?php 
            echo esc_attr($arrayFlag);
            ?>
][weight]" id="swp_engine_<?php 
            echo esc_attr($engine);
            ?>
_<?php 
            echo esc_attr($post_type->name);
            ?>
_<?php 
            echo esc_attr($arrayFlag);
            ?>
_weight" value="<?php 
            echo esc_attr($pdf_meta_weight);
            ?>
" />
									</td>
								</tr>
							<?php 
        }
        ?>

							<tr class="swp-custom-fields-heading">
								<td colspan="2">
									<strong><?php 
        _e('Custom Fields', 'searchwp');
        ?>
</strong>
								</td>
							</tr>

							<?php 
        if (isset($engineSettings[$post_type->name]['weights']['cf']) && is_array($engineSettings[$post_type->name]['weights']['cf']) && !empty($engineSettings[$post_type->name]['weights']['cf'])) {
            $cfWeights = $engineSettings[$post_type->name]['weights']['cf'];
            ?>
							<?php 
            foreach ($cfWeights as $cfFlag => $cfWeight) {
                $arrayFlag = str_replace('.', '', uniqid('swpp', true));
                ?>
								<?php 
                if ($cfWeight['metakey'] != SEARCHWP_PREFIX . 'content' && $cfWeight['metakey'] != SEARCHWP_PREFIX . 'pdf_metadata') {
                    /* handled elsewhere specifically */
                    ?>
									<tr class="swp-custom-field">
										<td class="swp-custom-field-select">
											<!--suppress HtmlFormInputWithoutLabel -->
											<select name="<?php 
                    echo esc_attr(SEARCHWP_PREFIX);
                    ?>
settings[engines][<?php 
                    echo esc_attr($engine);
                    ?>
][<?php 
                    echo esc_attr($post_type->name);
                    ?>
][weights][cf][<?php 
                    echo esc_attr($arrayFlag);
                    ?>
][metakey]" style="width:80%;">
												<option value="searchwpcfdefault" <?php 
                    selected($cfWeight['metakey'], 'searchwpcfdefault');
                    ?>
><?php 
                    _e('Any', 'searchwp');
                    ?>
</option>
												<?php 
                    if (!empty($searchwp->keys)) {
                        foreach ($searchwp->keys as $key) {
                            ?>
													<?php 
                            $meta_key_lower = function_exists('mb_strtolower') ? mb_strtolower($cfWeight['metakey'], 'UTF-8') : strtolower($cfWeight['metakey']);
                            $this_key_lower = function_exists('mb_strtolower') ? mb_strtolower($key, 'UTF-8') : strtolower($key);
                            ?>
													<option value="<?php 
                            echo esc_attr($key);
                            ?>
" <?php 
                            selected($meta_key_lower, $this_key_lower);
                            ?>
><?php 
                            echo esc_html($key);
                            ?>
</option>
												<?php 
                        }
                    }
                    ?>
											</select>
											<a class="swp-delete" href="#">x</a>
										</td>
										<td>
											<!--suppress HtmlFormInputWithoutLabel -->
											<input type="number" min="-1" step="0.1" class="small-text" name="<?php 
                    echo esc_attr(SEARCHWP_PREFIX);
                    ?>
settings[engines][<?php 
                    echo esc_attr($engine);
                    ?>
][<?php 
                    echo esc_attr($post_type->name);
                    ?>
][weights][cf][<?php 
                    echo esc_attr($arrayFlag);
                    ?>
][weight]" value="<?php 
                    echo esc_attr($cfWeight['weight']);
                    ?>
" />
										</td>
									</tr>
								<?php 
                }
                ?>
							<?php 
            }
        }
        ?>

							<tr>
								<td colspan="2">
									<a class="button swp-add-custom-field" href="#" data-engine="<?php 
        echo esc_attr($engine);
        ?>
" data-posttype="<?php 
        echo esc_attr($post_type->name);
        ?>
"><?php 
        _e('Add Custom Field', 'searchwp');
        ?>
</a>
									<a class="swp-tooltip swp-tooltip-custom-field" href="#swp-tooltip-custom-field-<?php 
        echo esc_attr($engine);
        ?>
_<?php 
        echo esc_attr($post_type->name);
        ?>
">?</a>
									<div class="swp-tooltip-content" id="swp-tooltip-custom-field-<?php 
        echo esc_attr($engine);
        ?>
_<?php 
        echo esc_attr($post_type->name);
        ?>
">
										<?php 
        _e('Include Custom Field data in search results. Meta values do not need to be plain strings, available keywords in metadata are extracted and indexed.', 'searchwp');
        ?>
									</div>
								</td>
							</tr>

						</tbody>
					</table>
				</div>
				<div class="swp-engine-options">
					<?php 
        $options = !empty($engineSettings[$post_type->name]['options']) ? $engineSettings[$post_type->name]['options'] : array();
        ?>
					<table>
						<tbody>
							<tr>
								<td>
									<label for="swp_engine_<?php 
        echo esc_attr($engine);
        ?>
_<?php 
        echo esc_attr($post_type->name);
        ?>
_exclude"><?php 
        _e('Exclude IDs: ', 'searchwp');
        ?>
</label>
								</td>
								<td>
									<?php 
        $options['exclude'] = isset($options['exclude']) ? (string) $options['exclude'] : '0';
        $options['exclude'] = SWP()->get_integer_csv_string_from_string_or_array($options['exclude']);
        ?>
									<input type="text" name="<?php 
        echo esc_attr(SEARCHWP_PREFIX);
        ?>
settings[engines][<?php 
        echo esc_attr($engine);
        ?>
][<?php 
        echo esc_attr($post_type->name);
        ?>
][options][exclude]" id="swp_engine_<?php 
        echo esc_attr($engine);
        ?>
_<?php 
        echo esc_attr($post_type->name);
        ?>
_exclude" placeholder="<?php 
        _e('Comma separated IDs', 'searchwp');
        ?>
" value="<?php 
        if (!empty($options['exclude'])) {
            echo esc_attr($options['exclude']);
        }
        ?>
" /> <a class="swp-tooltip" href="#swp-tooltip-exclude-<?php 
        echo esc_attr($engine);
        ?>
_<?php 
        echo esc_attr($post_type->name);
        ?>
">?</a>
									<div class="swp-tooltip-content" id="swp-tooltip-exclude-<?php 
        echo esc_attr($engine);
        ?>
_<?php 
        echo esc_attr($post_type->name);
        ?>
">
										<?php 
        _e('Comma separated post IDs. Will be excluded entirely, even if attributed to.', 'searchwp');
        ?>
									</div>
								</td>
							</tr>
							<?php 
        if (is_array($taxonomies) && count($taxonomies)) {
            foreach ($taxonomies as $taxonomy) {
                $taxonomy = get_taxonomy($taxonomy);
                $taxonomy_args = array('hide_empty' => false);
                $terms = get_terms($taxonomy->name, $taxonomy_args);
                if (!empty($terms)) {
                    ?>
									<tr>
										<td>
											<label for="swp_engine_<?php 
                    echo esc_attr($engine);
                    ?>
_<?php 
                    echo esc_attr($post_type->name);
                    ?>
_exclude_<?php 
                    echo esc_attr($taxonomy->name);
                    ?>
">
												<?php 
                    echo sprintf(__('Exclude %s:', 'searchwp'), esc_attr($taxonomy->labels->name));
                    ?>
											</label>
										</td>
										<td>
											<?php 
                    // retrieve our stored exclusions
                    $excluded = isset($options['exclude_' . $taxonomy->name]) ? explode(',', $options['exclude_' . $taxonomy->name]) : array();
                    if (!empty($excluded)) {
                        $excluded = array_map('absint', $excluded);
                    }
                    ?>
											<select class="swp-exclude-select" name="<?php 
                    echo esc_attr(SEARCHWP_PREFIX);
                    ?>
settings[engines][<?php 
                    echo esc_attr($engine);
                    ?>
][<?php 
                    echo esc_attr($post_type->name);
                    ?>
][options][exclude_<?php 
                    echo esc_attr($taxonomy->name);
                    ?>
][]" id="swp_engine_<?php 
                    echo esc_attr($engine);
                    ?>
_<?php 
                    echo esc_attr($post_type->name);
                    ?>
_exclude_<?php 
                    echo esc_attr($taxonomy->name);
                    ?>
" multiple data-placeholder="<?php 
                    _e('Leave blank to omit', 'searchwp');
                    ?>
" style="width:170px;">
												<?php 
                    foreach ($terms as $term) {
                        ?>
													<?php 
                        $selected = in_array($term->term_id, $excluded) ? ' selected="selected"' : '';
                        ?>
													<option value="<?php 
                        echo absint($term->term_id);
                        ?>
" <?php 
                        echo $selected;
                        ?>
><?php 
                        echo esc_html($term->name);
                        ?>
</option>
												<?php 
                    }
                    ?>
											</select>
											<a class="swp-tooltip" href="#swp-tooltip-exclude-<?php 
                    echo esc_attr($post_type->name);
                    ?>
-<?php 
                    echo esc_attr($taxonomy->name);
                    ?>
">?</a>
											<div class="swp-tooltip-content" id="swp-tooltip-exclude-<?php 
                    echo esc_attr($post_type->name);
                    ?>
-<?php 
                    echo esc_attr($taxonomy->name);
                    ?>
">
												<?php 
                    _e('Entries with these will be excluded entirely, even if attributed to.', 'searchwp');
                    ?>
											</div>
										</td>
									</tr>
								<?php 
                }
            }
        }
        ?>
							<?php 
        if ('attachment' == $post_type->name) {
            ?>
								<tr>
									<td>
										<label for="swp_engine_<?php 
            echo esc_attr($engine);
            ?>
_<?php 
            echo esc_attr($post_type->name);
            ?>
_mimes">
											<?php 
            echo __('Limit File Type(s) to', 'searchwp') . ': ';
            ?>
										</label>
									</td>
									<td>
										<?php 
            // TODO: needs better storage method
            $mimes = array(__('All Documents', 'searchwp'), __('PDFs', 'searchwp'), __('Plain Text', 'searchwp'), __('Images', 'searchwp'), __('Video', 'searchwp'), __('Audio', 'searchwp'));
            // retrieve our stored exclusions
            $limitedMimes = isset($options['mimes']) ? explode(',', $options['mimes']) : array();
            if (!empty($limitedMimes)) {
                $limitedMimes = array_map('absint', $limitedMimes);
            }
            ?>
										<select class="swp-exclude-select" name="<?php 
            echo esc_attr(SEARCHWP_PREFIX);
            ?>
settings[engines][<?php 
            echo esc_attr($engine);
            ?>
][<?php 
            echo esc_attr($post_type->name);
            ?>
][options][mimes][]" id="swp_engine_<?php 
            echo esc_attr($engine);
            ?>
_<?php 
            echo esc_attr($post_type->name);
            ?>
_mimes" multiple data-placeholder="<?php 
            _e('Leave blank to omit', 'searchwp');
            ?>
" style="width:170px;">
											<?php 
            for ($i = 0; $i < count($mimes); $i++) {
                ?>
												<?php 
                $selected = in_array($i, $limitedMimes) ? ' selected="selected"' : '';
                ?>
												<option value="<?php 
                echo esc_attr($i);
                ?>
" <?php 
                echo $selected;
                ?>
><?php 
                echo esc_html($mimes[$i]);
                ?>
</option>
											<?php 
            }
            ?>
										</select>
										<a class="swp-tooltip" href="#swp-tooltip-limit-<?php 
            echo esc_attr($post_type->name);
            ?>
-mime-<?php 
            echo esc_attr($engine);
            ?>
_<?php 
            echo esc_attr($post_type->name);
            ?>
">?</a>
										<div class="swp-tooltip-content" id="swp-tooltip-limit-<?php 
            echo esc_attr($post_type->name);
            ?>
-mime-<?php 
            echo esc_attr($engine);
            ?>
_<?php 
            echo esc_attr($post_type->name);
            ?>
">
											<?php 
            _e('If populated, Media results will be limited to these Media types', 'searchwp');
            ?>
										</div>
									</td>
								</tr>
							<?php 
        }
        ?>
							<?php 
        if ('attachment' == $post_type->name || apply_filters("searchwp_enable_parent_attribution_{$post_type->name}", false)) {
            ?>
								<tr>
									<td><?php 
            _e('Attribute post parent', 'searchwp');
            ?>
</td>
									<td>
										<?php 
            $enabled = !empty($options['parent']);
            ?>
										<input type="checkbox" name="<?php 
            echo esc_attr(SEARCHWP_PREFIX);
            ?>
settings[engines][<?php 
            echo esc_attr($engine);
            ?>
][<?php 
            echo esc_attr($post_type->name);
            ?>
][options][parent]" id="swp_engine_<?php 
            echo esc_attr($engine);
            ?>
_<?php 
            echo esc_attr($post_type->name);
            ?>
_parent" value="1" <?php 
            checked($enabled);
            ?>
/>
										<label for="swp_engine_<?php 
            echo esc_attr($engine);
            ?>
_<?php 
            echo esc_attr($post_type->name);
            ?>
_parent"><?php 
            _e('Enabled', 'searchwp');
            ?>
</label>
										<a class="swp-tooltip" href="#swp-tooltip-parent-<?php 
            echo esc_attr($engine);
            ?>
_<?php 
            echo esc_attr($post_type->name);
            ?>
">?</a>
										<div class="swp-tooltip-content" id="swp-tooltip-parent-<?php 
            echo esc_attr($engine);
            ?>
_<?php 
            echo esc_attr($post_type->name);
            ?>
">
											<?php 
            _e('When enabled, search weights will be applied to the post parent, not the post GUID', 'searchwp');
            ?>
										</div>
									</td>
								</tr>
							<?php 
        } elseif (apply_filters("searchwp_enable_attribution_{$post_type->name}", true)) {
            ?>
								<tr>
									<td>
										<label for="swp_engine_<?php 
            echo esc_attr($engine);
            ?>
_<?php 
            echo esc_attr($post_type->name);
            ?>
_attribute"><?php 
            _e('Attribute search results to ', 'searchwp');
            ?>
</label>
									</td>
									<td>
										<input type="number" min="1" step="1" name="<?php 
            echo esc_attr(SEARCHWP_PREFIX);
            ?>
settings[engines][<?php 
            echo esc_attr($engine);
            ?>
][<?php 
            echo esc_attr($post_type->name);
            ?>
][options][attribute_to]" id="swp_engine_<?php 
            echo esc_attr($engine);
            ?>
_<?php 
            echo esc_attr($post_type->name);
            ?>
_attribute_to" value="<?php 
            if (!empty($options['attribute_to'])) {
                echo esc_attr(absint($options['attribute_to']));
            }
            ?>
" placeholder="<?php 
            _e('Single post ID', 'searchwp');
            ?>
" />
										<a class="swp-tooltip" href="#swp-tooltip-attribute-<?php 
            echo esc_attr($engine);
            ?>
_<?php 
            echo esc_attr($post_type->name);
            ?>
">?</a>
										<div class="swp-tooltip-content" id="swp-tooltip-attribute-<?php 
            echo esc_attr($engine);
            ?>
_<?php 
            echo esc_attr($post_type->name);
            ?>
">
											<?php 
            _e("<strong>Expects single post ID</strong><br/>If permalinks for this post type should not be included in search results, you can have it's search weight count toward another post ID.", 'searchwp');
            ?>
										</div>
									</td>
								</tr>
							<?php 
        }
        ?>
							<?php 
        if (SWP()->is_stemming_supported_in_locale()) {
            ?>
								<tr>
									<td><?php 
            _e('Use keyword stem', 'searchwp');
            ?>
</td>
									<td>
										<?php 
            $enabled = !empty($options['stem']);
            ?>
										<input type="checkbox" name="<?php 
            echo esc_attr(SEARCHWP_PREFIX);
            ?>
settings[engines][<?php 
            echo esc_attr($engine);
            ?>
][<?php 
            echo esc_attr($post_type->name);
            ?>
][options][stem]" id="swp_engine_<?php 
            echo esc_attr($engine);
            ?>
_<?php 
            echo esc_attr($post_type->name);
            ?>
_stem" value="1" <?php 
            checked($enabled);
            ?>
/>
										<label for="swp_engine_<?php 
            echo esc_attr($engine);
            ?>
_<?php 
            echo esc_attr($post_type->name);
            ?>
_stem"><?php 
            _e('Enabled', 'searchwp');
            ?>
</label>
										<a class="swp-tooltip" href="#swp-tooltip-stem-<?php 
            echo esc_attr($engine);
            ?>
_<?php 
            echo esc_attr($post_type->name);
            ?>
">?</a>
										<div class="swp-tooltip-content" id="swp-tooltip-stem-<?php 
            echo esc_attr($engine);
            ?>
_<?php 
            echo esc_attr($post_type->name);
            ?>
">
											<?php 
            _e('<em>May increase search latency</em><br />For example: when enabled, searches for <strong>fishing</strong> and <strong>fished</strong> will generate the same results. When disabled, results may be different.', 'searchwp');
            ?>
										</div>
									</td>
								</tr>
							<?php 
        }
        ?>
						</tbody>
					</table>
				</div>
			</div>
		<?php 
    }
    ?>
	</div>
</div><?php 
    return true;
}
    /**
     * Output content in Plugin row if necessary
     */
    function plugin_row()
    {
        if (!class_exists('SearchWP')) {
            ?>
			<tr class="plugin-update-tr searchwp">
				<td colspan="3" class="plugin-update">
					<div class="update-message">
						<?php 
            esc_html_e('SearchWP must be active for Term Highlight to work', 'searchwp');
            ?>
					</div>
				</td>
			</tr>
			<?php 
        } else {
            $searchwp = SWP();
            if (version_compare($searchwp->version, '1.9.5', '<')) {
                ?>
				<tr class="plugin-update-tr searchwp">
					<td colspan="3" class="plugin-update">
						<div class="update-message">
							<?php 
                esc_html_e('SearchWP Term Highlight requires SearchWP 1.9.5 or greater', 'searchwp');
                ?>
						</div>
					</td>
				</tr>
			<?php 
            }
        }
    }