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'); ?> »</a></h3> <div class="inside"> <p><?php
function __construct() { $this->searchwp = SWP(); }
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 »</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( '/ /', ' ', $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 & 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 } } }