PluginProbe
WP Fast Total Search – The Power of Indexed Search / 1.81.282
WP Fast Total Search – The Power of Indexed Search v1.81.282
1.83.286 1.82.284 1.81.282 trunk 1.5.8 1.60.213 1.67.231 1.68.232 1.69.234 1.70.236 1.71.238 1.72.240 1.73.245 1.74.247 1.75.250 1.75.251 1.76.254 1.77.256 1.78.258 1.79.262 1.79.264 1.79.268 1.79.269 1.79.270 1.79.274 All 26 releases
fulltext-search / fulltext-search.php

fulltext-search.php in WP Fast Total Search – The Power of Indexed Search 1.81.282, at fulltext-search.php

901 lines 28.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /*
4 Plugin Name: WP Fast Total Search - The Power of Indexed Search
5 Description: Extends the default search with relevance, jet speed and ability to search any posts, metadata, taxonomy, shortcode content and any piece of the wordpress data. No external software/service required.
6 Version: 1.81.282
7 Tested up to: 7.0
8 Author: Epsiloncool
9 Author URI: https://e-wm.org
10 License: GPLv3
11 License URI: http://www.gnu.org/licenses/gpl-3.0.html
12 Text Domain: fulltext-search
13 Domain Path: /languages/
14 */
15
16 /**
17 * Copyright 2013-2026 Epsiloncool
18 *
19 * This program is free software: you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation, either version 3 of the License, or
22 * (at your option) any later version.
23 *
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
28 *
29 * You should have received a copy of the GNU General Public License
30 * along with this program. If not, see <http://www.gnu.org/licenses/>.
31 *
32 ******************************************************************************
33 * I am thank you for the help by buying PRO version of this plugin
34 * at https://fulltextsearch.org/
35 * It will keep me working further on this useful product.
36 ******************************************************************************
37 *
38 * @copyright 2013-2026
39 * @license GPLv3
40 * @version 1.81.282
41 * @package WP Fast Total Search
42 * @author Epsiloncool <info@e-wm.org>
43 */
44
45 /**
46 * ACE code editor
47 *
48 * BSD License
49 * Source: https://github.com/ajaxorg/ace
50 *
51 */
52 /**
53 * Json View
54 *
55 * MIT license
56 * Source: https://github.com/pgrabovets/json-view
57 */
58 /**
59 * PHP Stemmer
60 *
61 * MIT License
62 * Copyright (c) 2016 wamania
63 */
64
65 define('WPFTS_VERSION', '1.81.282');
66
67 if (file_exists(dirname(__FILE__).'/extensions/index.php')) {
68 require_once dirname(__FILE__).'/extensions/index.php';
69 }
70
71 require_once dirname(__FILE__).'/includes/wpfts_core.php';
72
73 add_action('cron_schedules', function($schedules)
74 {
75 $schedules['wpfts_each_minute'] = array(
76 'interval' => 60, // 60 seconds
77 'display' => __( 'Once a minute' )
78 );
79
80 $schedules['wpfts_each_hour'] = array(
81 'interval' => 3600, // 3600 seconds
82 'display' => __( 'Once a hour' )
83 );
84
85 return $schedules;
86 });
87
88 global $wpfts_core;
89
90 $wpfts_core = new WPFTS_Core();
91 $wpfts_core->root_dir = dirname(__FILE__);
92 $wpfts_core->Init();
93
94 require_once dirname(__FILE__).'/blocks/src/livesearch/index.php';
95
96 register_activation_hook(__FILE__, array(&$wpfts_core, 'activate_plugin'));
97 register_deactivation_hook(__FILE__, array(&$wpfts_core, 'deactivate_plugin'));
98
99 add_action( 'wpmu_new_blog', function ($blog_id, $user_id, $domain, $path, $site_id, $meta)
100 {
101 global $wpdb, $wpfts_core;
102
103 if (!function_exists('is_plugin_active_for_network')) {
104 require_once(ABSPATH.'/wp-admin/includes/plugin.php');
105 }
106
107 if (is_plugin_active_for_network(plugin_basename(__FILE__))) {
108 $old_blog = $wpdb->blogid;
109 switch_to_blog($blog_id);
110 $wpfts_core->_activate_plugin();
111 switch_to_blog($old_blog);
112 }
113 }, 10, 6);
114
115 add_action('wpfts_indexer_event', function()
116 {
117 global $wpfts_core;
118
119 if (!$wpfts_core) {
120 return;
121 }
122
123 if ($wpfts_core->_dev_debug) {
124 $wpfts_core->_flare->SendFire(array(
125 'pt' => 'inx_cron',
126 'stats' => array(
127
128 ),
129 ));
130 }
131
132 // Force indexer job to run
133 $wpfts_core->IndexerStart();
134 });
135
136 add_action('wpfts_log_clean', function()
137 {
138 global $wpfts_core;
139
140 if (!$wpfts_core) {
141 return;
142 }
143
144 $wpfts_core->ClearLogs();
145 });
146
147 add_action('wp_enqueue_scripts', function ()
148 {
149 global $wpfts_core;
150
151 if (($wpfts_core) && (intval($wpfts_core->get_option('is_smart_excerpts')) != 0)) {
152 //wp_enqueue_style( 'wpfts_front_styles', $wpfts_core->root_url.'/style/wpfts_front_styles.css', array(), WPFTS_VERSION);
153 echo '<style type="text/css">'.esc_html($wpfts_core->ReadSEStylesMinimized()).'</style>';
154 }
155
156 $version = (defined('WP_DEBUG') && WP_DEBUG) ? time() : WPFTS_VERSION;
157
158 wp_enqueue_style('wpfts_jquery-ui-styles', $wpfts_core->root_url.'/style/wpfts_autocomplete.css', array(), $version);
159 wp_enqueue_script('wpfts_frontend', plugins_url('js/wpfts_frontend.js', __FILE__), array('jquery', 'jquery-ui-autocomplete'), $version);
160 });
161
162 /**
163 * Here we need to deregister standard function that registers post-excerpt block and then register it with our own way
164 */
165 add_action('init', function(){
166 remove_action('init', 'register_block_core_post_excerpt', 10);
167 add_action('init', 'wpfts_register_block_core_post_excerpt', 10);
168 }, -32767);
169
170 /**
171 * Registers the `core/post-excerpt` block on the server, BUT with WPFTS specific renderer
172 *
173 * @since WP 5.8.0
174 */
175
176 function wpfts_register_block_core_post_excerpt()
177 {
178 $wp_include_dir_blocks = ABSPATH . WPINC . '/blocks';
179 register_block_type_from_metadata(
180 $wp_include_dir_blocks . '/post-excerpt',
181 array(
182 'render_callback' => 'wpfts_render_block_core_post_excerpt',
183 )
184 );
185 }
186
187
188 /**
189 * Renders the `core/post-excerpt` block on the server.
190 * NOTICE: This is a modified function originally taken from WP CORE (wp-includes/blocks/post-excerpt.php)
191 * WPFTS version does not use wp_trim_words, because it removes HTML tags from excerpts.
192 *
193 * SORRY, WP CORE DEVELOPERS, you had to think about filter that allow not to
194 *
195 * @since 5.8.0
196 *
197 * @param array $attributes Block attributes.
198 * @param string $content Block default content.
199 * @param WP_Block $block Block instance.
200 * @return string Returns the filtered post excerpt for the current post wrapped inside "p" tags.
201 */
202 function wpfts_render_block_core_post_excerpt($attributes, $content, $block)
203 {
204 global $wpfts_core;
205
206 if ($wpfts_core && is_object($wpfts_core)) {
207 if (!$wpfts_core->get_option('is_fix_blocks')) {
208 // Call native WP Blocks renderer in case we disabled ours
209 return render_block_core_post_excerpt($attributes, $content, $block);
210 }
211 } else {
212 // Wrong call, WPFTS not exists
213 return '';
214 }
215
216 if ( ! isset( $block->context['postId'] ) ) {
217 return '';
218 }
219
220 /*
221 * The purpose of the excerpt length setting is to limit the length of both
222 * automatically generated and user-created excerpts.
223 * Because the excerpt_length filter only applies to auto generated excerpts,
224 * wp_trim_words is used instead.
225 */
226 //$excerpt_length = $attributes['excerptLength']; // This change was done for WPFTS
227 $excerpt = get_the_excerpt( $block->context['postId'] );
228
229 /* This change was done for WPFTS
230 if ( isset( $excerpt_length ) ) {
231 $excerpt = wp_trim_words( $excerpt, $excerpt_length );
232 }
233 */
234
235 $more_text = ! empty( $attributes['moreText'] ) ? '<a class="wp-block-post-excerpt__more-link" href="' . esc_url( get_the_permalink( $block->context['postId'] ) ) . '">' . wp_kses_post( $attributes['moreText'] ) . '</a>' : '';
236 $filter_excerpt_more = static function ( $more ) use ( $more_text ) {
237 return empty( $more_text ) ? $more : '';
238 };
239 /**
240 * Some themes might use `excerpt_more` filter to handle the
241 * `more` link displayed after a trimmed excerpt. Since the
242 * block has a `more text` attribute we have to check and
243 * override if needed the return value from this filter.
244 * So if the block's attribute is not empty override the
245 * `excerpt_more` filter and return nothing. This will
246 * result in showing only one `read more` link at a time.
247 */
248 add_filter( 'excerpt_more', $filter_excerpt_more );
249 $classes = array();
250 if ( isset( $attributes['textAlign'] ) ) {
251 $classes[] = 'has-text-align-' . $attributes['textAlign'];
252 }
253 if ( isset( $attributes['style']['elements']['link']['color']['text'] ) ) {
254 $classes[] = 'has-link-color';
255 }
256 $wrapper_attributes = get_block_wrapper_attributes( array( 'class' => implode( ' ', $classes ) ) );
257
258 $content = '<p class="wp-block-post-excerpt__excerpt">' . $excerpt;
259 $show_more_on_new_line = ! isset( $attributes['showMoreOnNewLine'] ) || $attributes['showMoreOnNewLine'];
260 if ( $show_more_on_new_line && ! empty( $more_text ) ) {
261 $content .= '</p><p class="wp-block-post-excerpt__more-text">' . $more_text . '</p>';
262 } else {
263 $content .= " $more_text</p>";
264 }
265 remove_filter( 'excerpt_more', $filter_excerpt_more );
266 return sprintf( '<div %1$s>%2$s</div>', $wrapper_attributes, $content );
267
268 }
269
270 add_action('init', function ()
271 {
272 global $wpfts_core;
273
274 if ((is_object($wpfts_core)) && (is_callable(array($wpfts_core, 'set_hooks')))) {
275
276 $wpfts_core->set_hooks();
277
278 add_action('wp_ajax_nopriv_wpfts_autocomplete', 'wpfts_autocomplete_proc');
279 add_action('wp_ajax_wpfts_autocomplete', 'wpfts_autocomplete_proc');
280
281 add_action('wp_ajax_nopriv_wpfts_force_index', array($wpfts_core, 'ajax_force_index'));
282 add_action('wp_ajax_wpfts_force_index', array($wpfts_core, 'ajax_force_index'));
283
284 /** Sorry, but my HTML code sometimes has this */
285 add_filter( 'safe_style_css', function( $styles ) {
286 $styles[] = 'display';
287 return $styles;
288 });
289
290 /**
291 * Small info row for Post Submit Meta Box
292 */
293 add_action('post_submitbox_misc_actions', function($post)
294 {
295 global $wpfts_core;
296
297 ?>
298 <div class="misc-pub-section curtime misc-pub-curtime wpfts_submitbox_block">
299 <span class="dashicons-before dashicons-search wpfts_submitbox_icon">
300 <?php echo esc_html(__('Index', 'fulltext-search')).':'; ?>
301 <?php
302
303 // Get current post status
304 if ($post && is_object($post) && isset($post->ID)) {
305 $post_id = $post->ID;
306
307 $st = $wpfts_core->GetPostIndexStatus(array($post_id));
308
309 echo '<span class="wpfts_post_status" data-postid="'.esc_attr($post_id).'">'.esc_html($st['p'.$post_id]['status_text']).'</span>';
310 }
311
312 /*
313 <a href="#edit_timestamp" class="edit-timestamp hide-if-no-js" role="button">
314 <span aria-hidden="true"><?php echo __( 'More', 'fulltext-search' ); ?></span>
315 <span class="screen-reader-text"><?php echo __( 'More actions', 'fulltext-search' ); ?></span>
316 </a>
317 <fieldset id="timestampdiv" class="hide-if-js">
318 <legend class="screen-reader-text"><?php _e( 'Date and time' ); ?></legend>
319
320 </fieldset>
321 */ ?>
322 </span>
323 </div>
324 <?php
325 });
326
327 if (is_admin()) {
328
329 add_action('admin_menu', 'wpfts_admin_menu');
330 add_filter('plugin_row_meta', 'wpfts_plugin_links', 10, 2);
331
332 load_plugin_textdomain( 'fulltext-search', false, basename(dirname(__FILE__)).'/languages/');
333
334 add_action('admin_enqueue_scripts', 'wpfts_enqueues');
335
336 add_action('wp_ajax_wpftsi_ping', array($wpfts_core, 'ajax_ping'));
337 add_action('wp_ajax_wpftsi_set_pause', array($wpfts_core, 'ajax_set_pause'));
338 add_action('wp_ajax_wpftsi_hide_notification', array($wpfts_core, 'ajax_hide_notification'));
339 add_action('wp_ajax_wpftsi_se_style_preview', array($wpfts_core, 'ajax_se_style_preview'));
340 add_action('wp_ajax_wpftsi_se_style_reset', array($wpfts_core, 'ajax_se_style_reset'));
341 add_action('wp_ajax_wpftsi_try_updatedb', array($wpfts_core, 'ajax_try_updatedb'));
342
343 $admin_actions = $wpfts_core->getAdminActions();
344
345 add_action('wp_ajax_wpftsi_submit_testpost', array($admin_actions, 'ajax_submit_testpost'));
346 add_action('wp_ajax_wpftsi_submit_testsearch', array($admin_actions, 'ajax_submit_testsearch'));
347 add_action('wp_ajax_wpftsi_submit_rebuild', array($admin_actions, 'ajax_submit_rebuild'));
348 add_action('wp_ajax_wpftsi_smartform', array($admin_actions, 'ajax_smartform'));
349 add_action('wp_ajax_wpftsi_submit_upgradeindex', array($admin_actions, 'ajax_upgradeindex'));
350 add_action('wp_ajax_wpftsi_add_user_irule', array($admin_actions, 'ajax_add_user_irule'));
351
352 $wpfts_core->FeatureDetector();
353 }
354
355 do_action('wpfts_init_addons');
356 }
357 });
358
359 // Collect all the irules data
360 // All the custom IRules should be defined in or before 'init' hook (fine for plugins and functions.php file)
361 add_action('init', function()
362 {
363 global $wpfts_core;
364
365 if ((is_object($wpfts_core)) && (is_callable(array($wpfts_core, 'collect_irules')))) {
366 $wpfts_core->collect_irules();
367 if (is_admin()) {
368 $wpfts_core->FeatureDetectorAfterInitAdmin();
369 }
370 }
371 }, 32767);
372
373 function wpfts_custom_js()
374 {
375 global $wpfts_core, $wpfts_gstatus;
376
377 $wpfts_gstatus = $wpfts_core->get_status();
378 $mid = $wpfts_core->get_option('flare_mid');
379
380 $is_settings = $wpfts_core->is_wpfts_settings_page ? 1 : 0;
381
382 $lang_texts = array(
383 'save_changes' => esc_html(__('Save Changes', 'fulltext-search')),
384 'changes_not_set' => esc_html(__('Changes was not saved - an error occured!', 'fulltext-search')),
385 'link_follows' => esc_html(__("This link follows to\n\n%s", 'fulltext-search')),
386 'reset_styles' => esc_html(__('This action will reset your custom CSS styles, are you sure?', 'fulltext-search')),
387 );
388
389 ?><script type="text/javascript">
390 var wpfts_pid = "<?php echo esc_html($wpfts_core->getPid()); ?>";
391 var wpfts_pingtimeout = <?php echo intval($wpfts_core->get_option('ping_period')) * 1000; ?>;
392 var wpfts_root_url = "<?php echo esc_html($wpfts_core->root_url); ?>";
393 var switch_caution_txt = <?php echo wpfts_json_encode(__("The conversion process will take some time,\nduring which you should stay on this page of the browser.\n\nIf the progress value does not change for more than 2 minutes,\nrefresh the page manually.", 'fulltext-search')); ?>;
394 var wpfts_is_settings_screen = <?php echo intval($is_settings); ?>;
395 document.wpfts_settings_main_page = '<?php echo 'admin.php?page=wpfts-options'; ?>';
396 document.wpfts_lang_texts = <?php echo wpfts_json_encode($lang_texts); ?>;
397 document.wpfts_mid = "<?php echo esc_html(addslashes($mid)); ?>";
398 document.wpfts_last_ts = <?php echo isset($wpfts_gstatus['ts']) ? intval($wpfts_gstatus['ts']) : 0; ?>;
399 document.nonce_setpause = "<?php echo wp_create_nonce( 'setpause_nonce' ); ?>";
400
401 </script><?php
402
403 $version = (defined('WP_DEBUG') && WP_DEBUG) ? time() : WPFTS_VERSION;
404
405 //$current_tab = isset($_GET['page']) ? $_GET['page'] : 'wpfts-options';
406 //if ($current_tab == 'wpfts-options-search-relevance') {
407 ?>
408 <script type="text/javascript">
409 var wpfts_se_styles_editor = null;
410 jQuery(document).ready(function()
411 {
412 if (jQuery('#wpfts_se_styles_editor').length > 0) {
413 if (ace) {
414 wpfts_se_styles_editor = ace.edit("wpfts_se_styles_editor");
415 wpfts_se_styles_editor.setTheme("ace/theme/chrome");
416 wpfts_se_styles_editor.session.setMode("ace/mode/css");
417
418 if (wpfts_se_styles_editor && (jQuery('#wpfts_se_styles_editor_hidden').length > 0)) {
419 wpfts_se_styles_editor.session.on('change', function()
420 {
421 jQuery('#wpfts_se_styles_editor_hidden').val(wpfts_se_styles_editor.session.getValue());
422 jQuery('#wpfts_se_styles_editor_hidden').trigger('change');
423 });
424 }
425 }
426 }
427
428 });
429 </script>
430 <?php
431 //}
432 }
433 add_action('admin_head', 'wpfts_custom_js');
434
435 function wpfts_frontend_js()
436 {
437 ?><script type="text/javascript">
438 document.wpfts_ajaxurl = "<?php echo esc_url(admin_url('admin-ajax.php')); ?>";
439 </script><?php
440 }
441 add_action('wp_head', 'wpfts_frontend_js');
442
443 add_action('widgets_init', function()
444 {
445 require_once dirname(__FILE__).'/includes/widgets/wpfts_widget.class.php';
446 register_widget('WPFTS_Custom_Widget');
447 });
448
449 function wpfts_autocomplete_proc()
450 {
451 $res = array();
452
453 $form_data = isset($_POST['form_data']) ? $_POST['form_data'] : array();
454
455 if (is_array($form_data)) {
456 $widget_code = isset($form_data['wpfts_wdgt']) ? $form_data['wpfts_wdgt'] : '';
457 $s = isset($form_data['s']) ? $form_data['s'] : '';
458
459 $params = $form_data;
460 $params['wpfts_is_force'] = 1; // Force WPFTS
461 $params['wpfts_source'] = 'wpfts_autocomplete_ajax'; // Specify that we are calling from here
462
463 if (strlen($widget_code) > 0) {
464 $params['wpfts_wdgt'] = $widget_code;
465 } else {
466 // Set default parameters like WP does (for Main Query)
467 $params['post_status'] = 'publish';
468 }
469 $loop = new WP_Query($params);
470
471 global $wpfts_core;
472
473 if ($wpfts_core) {
474 $wpfts_core->ForceSmartExcerpts($s);
475 }
476
477 while ($loop->have_posts()) {
478 $loop->the_post();
479
480 $res[] = array(
481 'label' => get_the_title(),
482 'link' => get_permalink(),
483 );
484 }
485 wp_reset_query();
486 }
487
488 echo wpfts_json_encode($res);
489 exit();
490 }
491
492 add_action('plugins_loaded', 'wpfts_load_plugin_textdomain');
493 function wpfts_load_plugin_textdomain() {
494 load_plugin_textdomain( 'fulltext-search', false, dirname(plugin_basename(__FILE__)).'/languages/');
495 }
496
497 function wpfts_plugin_links($links, $file)
498 {
499 if (basename($file) == basename(__FILE__)) {
500 //$links[] = '<a href="admin.php?page=wpfts-options">'.__('Settings', 'fulltext-search').'</a>';
501 }
502 return $links;
503 }
504
505 add_filter('plugin_action_links_'.plugin_basename(__FILE__), function($links)
506 {
507 array_unshift($links, '<a href="'.admin_url('admin.php?page=wpfts-options').'">'.__('Settings', 'fulltext-search').'</a>');
508 return $links;
509 });
510
511 function wpfts_admin_menu()
512 {
513 global $wpfts_core;
514
515 //$position = ( ++$GLOBALS['_wp_last_object_menu'] );
516 $position = ( ++$GLOBALS['_wp_last_utility_menu'] );
517
518 $parent_menu = add_menu_page(__('Fast Total Search', 'fulltext-search'), __('Fast Total Search', 'fulltext-search'), 'manage_options', 'wpfts-options', 'wpfts_option_page', 'dashicons-search', $position);
519
520 $wpfts_core->SetTopLevelScreen($parent_menu);
521
522 $menu_items = array(
523 'wpfts-options' => array(__('Main Configuration', 'fulltext-search')),
524 'wpfts-options-indexing-engine' => array(__('Indexing Engine Settings', 'fulltext-search'), __('Indexing Engine', 'fulltext-search')),
525 'wpfts-options-search-relevance' => array(__('Search & Output', 'fulltext-search')),
526 'wpfts-options-sandbox-area' => array(__('Sandbox Area', 'fulltext-search')),
527 'wpfts-options-analytics' => array(__('Analytics', 'fulltext-search')),
528 //'wpfts-options-addons' => array(__('Addons', 'fulltext-search')),
529 'wpfts-options-support' => array(__('Support & Docs', 'fulltext-search')),
530 );
531 $ps1_start = $wpfts_core->get_option('ps1_start_dt');
532 if ((strlen($ps1_start) > 0) && ((strtotime($ps1_start) + 24 * 3600 * 14) < current_time('timestamp'))) {
533 $menu_items['wpfts-options-ps'] = array(__('Partnership', 'fulltext-search'));
534 }
535
536 $menu_items = apply_filters('wpfts_admin_menu_items', $menu_items);
537
538 $matches = array();
539 $is_set_prefix = false;
540 foreach ($menu_items as $k => $d) {
541 $tt = add_submenu_page('wpfts-options', $d[0], (isset($d[1]) && $d[1]) ? $d[1] : $d[0], 'manage_options', $k, (isset($d[2]) && function_exists($d[2])) ? $d[2] : 'wpfts_option_page');
542 if ((substr($tt, 0, 8) != 'toplevel') && (!$is_set_prefix)) {
543 if (preg_match('~^(.+_wpfts\-options).*~u', $tt, $matches)) {
544 $is_set_prefix = true;
545 $wpfts_core->SetPrefixScreen($matches[1]);
546 }
547 }
548 }
549
550 add_filter('plugin_action_links', 'wpfts_settings_link', 10, 2);
551
552 do_action('wpfts_admin_menu');
553 }
554
555 function wpfts_enqueues($hook_suffix)
556 {
557 global $wpfts_core;
558
559 $version = (defined('WP_DEBUG') && WP_DEBUG) ? time() : WPFTS_VERSION;
560
561 $wpfts_core->set_is_settings_page();
562
563 wp_enqueue_style('wpfts_style', plugins_url('style/wpfts_main.css', __FILE__), array(), $version);
564 wp_enqueue_script('wpfts_script', plugins_url('js/wpfts_script.js', __FILE__), array(), $version);
565 wp_enqueue_script('wpfts_jsonview', plugins_url('js/jsonview.js', __FILE__), array(), $version);
566
567 if ($wpfts_core->is_wpfts_settings_page) {
568
569 wp_enqueue_style('wpfts_style_bs', plugins_url('style/bs_wpfts.css', __FILE__), array(), $version);
570 wp_enqueue_style('wpfts_style_ui', plugins_url('style/ui_main.css', __FILE__), array(), $version);
571 wp_enqueue_style('wpfts_style_fa', plugins_url('style/fontawesome-all.css', __FILE__), array(), $version);
572 wp_enqueue_style('wpfts_style_s2', plugins_url('style/select2/select2.min.css', __FILE__), array(), $version);
573
574 wp_enqueue_script('wpfts_script_bs', plugins_url('js/bootstrap.min.js', __FILE__), array('jquery'), $version);
575 wp_enqueue_script('wpfts_script_ui', plugins_url('js/ui_main.js', __FILE__), array(), $version);
576 wp_enqueue_script('wpfts_script_s2', plugins_url('js/select2/select2.min.js', __FILE__), array(), $version);
577
578 wp_enqueue_script('wpfts_ace_script', plugins_url('classes/ace/ace.js', __FILE__), array('jquery'), $version);
579
580 // Remove welcome_message
581 $wpfts_core->set_option('is_welcome_message', '');
582
583 wp_enqueue_style('wp-pointer');
584
585 wp_enqueue_script('postbox');
586 wp_enqueue_script('wp-pointer');
587 }
588
589 do_action('wpfts_admin_scripts');
590 }
591
592 function wpfts_settings_link($links, $file)
593 {
594 $this_plugin = dirname(plugin_basename(dirname(__FILE__))) . '/fulltext-search.php';
595 if ($file == $this_plugin) {
596 $links[] = '<a href="admin.php?page=wpfts-options">' . __('Settings', 'fulltext-search' ) . '</a>';
597 }
598 return $links;
599 }
600
601 function wpfts_option_page()
602 {
603 global $wpfts_core;
604
605 if (!current_user_can('manage_options')) {
606 wp_die(esc_html(__('Sorry, but you do not have permissions to change settings.', 'fulltext-search')));
607 }
608
609 /* Make sure post was from this page */
610 if (isset($_POST) && (count($_POST) > 0)) {
611 check_admin_referer('wpfts-options');
612 }
613
614 $wpfts_core->set_option('is_welcome_message', '');
615
616 require dirname(__FILE__).'/admin/admin_page.php';
617 }
618
619 function WPFTS_Get_Widget_List()
620 {
621 global $wpfts_core;
622
623 if ($wpfts_core && is_object($wpfts_core) && (is_a($wpfts_core, 'WPFTS_Core'))) {
624 return $wpfts_core->GetWidgetPresets();
625 }
626
627 return array();
628 }
629
630 /**
631 * Called when any post/page/etc updated or created
632 *
633 * We need to reindex the post by this action
634 */
635 function wpfts_save_post_action($post_id)
636 {
637 wpfts_post_reindex($post_id);
638 }
639 add_action('save_post', 'wpfts_save_post_action', 99);
640
641 /**
642 * Called when any post/page/etc was deleted
643 *
644 * We need to delete the post from the index by this action
645 */
646 function wpfts_deleted_post_action($post_id)
647 {
648 wpfts_post_reindex($post_id);
649 }
650 add_action('after_delete_post', 'wpfts_deleted_post_action', 99);
651
652 function wpfts_post_reindex($post_id, $is_force_remove = false, $is_raw_cache_remove = false)
653 {
654 global $wpfts_core;
655
656 if ($is_raw_cache_remove) {
657 $wpfts_core->removeRawCache($post_id);
658 }
659
660 // First, let's force sync
661 $wpfts_core->MakePostsSync(true);
662
663 // Make some magic to force this post indexed first
664 $q = 'update `wpftsi_index` set force_rebuild = 2 where tid = "'.addslashes($post_id).'" and tsrc = "wp_posts"';
665 $wpfts_core->db->query($q);
666
667 // Force status recalculation
668 $wpfts_core->set_option('status_next_ts', 0);
669
670 // Break current loop to start over
671 $wpfts_core->set_option('is_break_loop', 1);
672
673 // Ensure loop is starting
674 $wpfts_core->CallIndexerStartNoBlocking();
675
676 /*
677 $res = $wpfts_core->reindex_post($post_id, $is_force_remove);
678
679 if (!$res) {
680 trigger_error('Error reindex post ID='.$post_id.': '.$wpfts_core->index_error, E_USER_NOTICE);
681 return false;
682 }
683 */
684
685 return true;
686 }
687
688 function wpfts_set_pause($is_on = true, $is_start_indexer = false)
689 {
690 global $wpfts_core;
691
692 if ($wpfts_core) {
693 return $wpfts_core->SetPause($is_on, $is_start_indexer);
694 }
695
696 return false;
697 }
698
699 /** Smart Excerpts filters */
700 add_filter('the_title', function($out)
701 {
702 global $wpfts_core;
703
704 if ($wpfts_core && is_a($wpfts_core, 'WPFTS_Core')) {
705 $is_smart_excerpts = intval($wpfts_core->get_option('is_smart_excerpts'));
706 if ($is_smart_excerpts != 0) {
707
708 $loop_or_block = in_the_loop();
709 if (!$loop_or_block) {
710 if (class_exists('WP_Block_Supports')) {
711 if (isset(WP_Block_Supports::$block_to_render['blockName'])) {
712 $bn = WP_Block_Supports::$block_to_render['blockName'];
713 if (preg_match('~\/post\-title$~', $bn)) {
714 $loop_or_block = true;
715 }
716 }
717 }
718 }
719
720 if ((is_search() && !is_admin() && $loop_or_block) || ($wpfts_core->forced_se_query !== false)) {
721 $post = get_post();
722 $ri = new WPFTS_Result_Item(0, $post);
723 return $ri->TitleText($out);
724 }
725 }
726 }
727
728 return $out;
729 });
730
731 add_filter('attachment_link', function($link, $post_id)
732 {
733 global $wpfts_core;
734
735 if ($wpfts_core && is_a($wpfts_core, 'WPFTS_Core')) {
736 $is_smart_excerpts = intval($wpfts_core->get_option('is_smart_excerpts'));
737 if ($is_smart_excerpts != 0) {
738
739 $loop_or_block = in_the_loop();
740 if (!$loop_or_block) {
741 if (class_exists('WP_Block_Supports')) {
742 if (isset(WP_Block_Supports::$block_to_render['blockName'])) {
743 $bn = WP_Block_Supports::$block_to_render['blockName'];
744 if (preg_match('~\/post\-title$~', $bn)) {
745 $loop_or_block = true;
746 }
747 }
748 }
749 }
750
751 if ((is_search() && !is_admin() && $loop_or_block) || ($wpfts_core->forced_se_query !== false)) {
752 $ri = new WPFTS_Result_Item($post_id);
753 return $ri->TitleLink($link);
754 }
755 }
756 }
757
758 return $link;
759 }, 10, 2);
760
761 add_filter('page_link', function($link, $post_id, $leavename)
762 {
763 global $wpfts_core;
764
765 if ($wpfts_core && is_a($wpfts_core, 'WPFTS_Core')) {
766 $is_smart_excerpts = intval($wpfts_core->get_option('is_smart_excerpts'));
767 if ($is_smart_excerpts != 0) {
768
769 $loop_or_block = in_the_loop();
770 if (!$loop_or_block) {
771 if (class_exists('WP_Block_Supports')) {
772 if (isset(WP_Block_Supports::$block_to_render['blockName'])) {
773 $bn = WP_Block_Supports::$block_to_render['blockName'];
774 if (preg_match('~\/post\-title$~', $bn)) {
775 $loop_or_block = true;
776 }
777 }
778 }
779 }
780
781 if ((is_search() && !is_admin() && $loop_or_block) || ($wpfts_core->forced_se_query !== false)) {
782 $ri = new WPFTS_Result_Item($post_id);
783 return $ri->TitleLink($link);
784 }
785 }
786 }
787
788 return $link;
789 }, 10, 3);
790
791 add_filter('post_type_link', function($link, $post, $leavename)
792 {
793 global $wpfts_core;
794
795 if ($wpfts_core && is_a($wpfts_core, 'WPFTS_Core')) {
796 $is_smart_excerpts = intval($wpfts_core->get_option('is_smart_excerpts'));
797 if ($is_smart_excerpts != 0) {
798
799 $loop_or_block = in_the_loop();
800 if (!$loop_or_block) {
801 if (class_exists('WP_Block_Supports')) {
802 if (isset(WP_Block_Supports::$block_to_render['blockName'])) {
803 $bn = WP_Block_Supports::$block_to_render['blockName'];
804 if (preg_match('~\/post\-title$~', $bn)) {
805 $loop_or_block = true;
806 }
807 }
808 }
809 }
810
811 if ((is_search() && !is_admin() && $loop_or_block) || ($wpfts_core->forced_se_query !== false)) {
812 $ri = new WPFTS_Result_Item(0, $post);
813 return $ri->TitleLink($link);
814 }
815 }
816 }
817
818 return $link;
819 }, 10, 3);
820
821 add_filter('post_link', function($link, $post, $leavename)
822 {
823 global $wpfts_core;
824
825 if ($wpfts_core && is_a($wpfts_core, 'WPFTS_Core')) {
826 $is_smart_excerpts = intval($wpfts_core->get_option('is_smart_excerpts'));
827 if ($is_smart_excerpts != 0) {
828
829 $loop_or_block = in_the_loop();
830 if (!$loop_or_block) {
831 if (class_exists('WP_Block_Supports')) {
832 if (isset(WP_Block_Supports::$block_to_render['blockName'])) {
833 $bn = WP_Block_Supports::$block_to_render['blockName'];
834 if (preg_match('~\/post\-title$~', $bn)) {
835 $loop_or_block = true;
836 }
837 }
838 }
839 }
840
841 if ((is_search() && !is_admin() && $loop_or_block) || ($wpfts_core->forced_se_query !== false)) {
842 $ri = new WPFTS_Result_Item(0, $post);
843 return $ri->TitleLink($link);
844 }
845 }
846 }
847
848 return $link;
849 }, 10, 3);
850
851 add_filter('get_the_excerpt', function($out)
852 {
853 global $wpfts_core;
854
855 if ($wpfts_core && is_a($wpfts_core, 'WPFTS_Core')) {
856
857 $is_smart_excerpts = intval($wpfts_core->get_option('is_smart_excerpts'));
858 if ($is_smart_excerpts != 0) {
859
860 $post = get_post();
861
862 $loop_or_block = in_the_loop();
863 if (!$loop_or_block) {
864 if (class_exists('WP_Block_Supports')) {
865 if (isset(WP_Block_Supports::$block_to_render['blockName'])) {
866 $bn = WP_Block_Supports::$block_to_render['blockName'];
867 if (preg_match('~\/post\-excerpt$~', $bn)) {
868 $loop_or_block = true;
869 }
870 }
871 }
872 }
873
874 if (is_search() && !is_admin() && $loop_or_block) {
875
876 $ri = new WPFTS_Result_Item(0, $post);
877 $query = get_search_query(false);
878 $out = '<div class="wpfts-result-item">'.$ri->Excerpt($query).'</div>';
879 return $out;
880 } elseif ($wpfts_core->forced_se_query !== false) {
881 $ri = new WPFTS_Result_Item(0, $post);
882 $query = $wpfts_core->forced_se_query;
883 $out = '<div class="wpfts-result-item">'.$ri->Excerpt($query).'</div>';
884 return $out;
885 } else {
886 // Leave excerpt unchanged
887 }
888 }
889 }
890
891 return $out;
892 });
893
894 /**
895 * Convert HTML "<" and ">" and also quotes to unicode entities to prevent XSS attacks
896 */
897 function wpfts_json_encode($data)
898 {
899 return wp_json_encode($data, JSON_HEX_TAG | JSON_HEX_QUOT);
900 }
901