PluginProbe
WP Fast Total Search – The Power of Indexed Search / 1.82.284
WP Fast Total Search – The Power of Indexed Search v1.82.284
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.82.284, at fulltext-search.php

902 lines 28.8 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.82.284
7 Tested up to: 7.0.2
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.82.284
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.82.284');
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 document.nonce_forceindex = "<?php echo wp_create_nonce( 'forceindex_nonce' ); ?>";
401
402 </script><?php
403
404 $version = (defined('WP_DEBUG') && WP_DEBUG) ? time() : WPFTS_VERSION;
405
406 //$current_tab = isset($_GET['page']) ? $_GET['page'] : 'wpfts-options';
407 //if ($current_tab == 'wpfts-options-search-relevance') {
408 ?>
409 <script type="text/javascript">
410 var wpfts_se_styles_editor = null;
411 jQuery(document).ready(function()
412 {
413 if (jQuery('#wpfts_se_styles_editor').length > 0) {
414 if (ace) {
415 wpfts_se_styles_editor = ace.edit("wpfts_se_styles_editor");
416 wpfts_se_styles_editor.setTheme("ace/theme/chrome");
417 wpfts_se_styles_editor.session.setMode("ace/mode/css");
418
419 if (wpfts_se_styles_editor && (jQuery('#wpfts_se_styles_editor_hidden').length > 0)) {
420 wpfts_se_styles_editor.session.on('change', function()
421 {
422 jQuery('#wpfts_se_styles_editor_hidden').val(wpfts_se_styles_editor.session.getValue());
423 jQuery('#wpfts_se_styles_editor_hidden').trigger('change');
424 });
425 }
426 }
427 }
428
429 });
430 </script>
431 <?php
432 //}
433 }
434 add_action('admin_head', 'wpfts_custom_js');
435
436 function wpfts_frontend_js()
437 {
438 ?><script type="text/javascript">
439 document.wpfts_ajaxurl = "<?php echo esc_url(admin_url('admin-ajax.php')); ?>";
440 </script><?php
441 }
442 add_action('wp_head', 'wpfts_frontend_js');
443
444 add_action('widgets_init', function()
445 {
446 require_once dirname(__FILE__).'/includes/widgets/wpfts_widget.class.php';
447 register_widget('WPFTS_Custom_Widget');
448 });
449
450 function wpfts_autocomplete_proc()
451 {
452 $res = array();
453
454 $form_data = isset($_POST['form_data']) ? $_POST['form_data'] : array();
455
456 if (is_array($form_data)) {
457 $widget_code = isset($form_data['wpfts_wdgt']) ? $form_data['wpfts_wdgt'] : '';
458 $s = isset($form_data['s']) ? $form_data['s'] : '';
459
460 $params = $form_data;
461 $params['wpfts_is_force'] = 1; // Force WPFTS
462 $params['wpfts_source'] = 'wpfts_autocomplete_ajax'; // Specify that we are calling from here
463
464 if (strlen($widget_code) > 0) {
465 $params['wpfts_wdgt'] = $widget_code;
466 } else {
467 // Set default parameters like WP does (for Main Query)
468 $params['post_status'] = 'publish';
469 }
470 $loop = new WP_Query($params);
471
472 global $wpfts_core;
473
474 if ($wpfts_core) {
475 $wpfts_core->ForceSmartExcerpts($s);
476 }
477
478 while ($loop->have_posts()) {
479 $loop->the_post();
480
481 $res[] = array(
482 'label' => get_the_title(),
483 'link' => get_permalink(),
484 );
485 }
486 wp_reset_query();
487 }
488
489 echo wpfts_json_encode($res);
490 exit();
491 }
492
493 add_action('plugins_loaded', 'wpfts_load_plugin_textdomain');
494 function wpfts_load_plugin_textdomain() {
495 load_plugin_textdomain( 'fulltext-search', false, dirname(plugin_basename(__FILE__)).'/languages/');
496 }
497
498 function wpfts_plugin_links($links, $file)
499 {
500 if (basename($file) == basename(__FILE__)) {
501 //$links[] = '<a href="admin.php?page=wpfts-options">'.__('Settings', 'fulltext-search').'</a>';
502 }
503 return $links;
504 }
505
506 add_filter('plugin_action_links_'.plugin_basename(__FILE__), function($links)
507 {
508 array_unshift($links, '<a href="'.admin_url('admin.php?page=wpfts-options').'">'.__('Settings', 'fulltext-search').'</a>');
509 return $links;
510 });
511
512 function wpfts_admin_menu()
513 {
514 global $wpfts_core;
515
516 //$position = ( ++$GLOBALS['_wp_last_object_menu'] );
517 $position = ( ++$GLOBALS['_wp_last_utility_menu'] );
518
519 $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);
520
521 $wpfts_core->SetTopLevelScreen($parent_menu);
522
523 $menu_items = array(
524 'wpfts-options' => array(__('Main Configuration', 'fulltext-search')),
525 'wpfts-options-indexing-engine' => array(__('Indexing Engine Settings', 'fulltext-search'), __('Indexing Engine', 'fulltext-search')),
526 'wpfts-options-search-relevance' => array(__('Search & Output', 'fulltext-search')),
527 'wpfts-options-sandbox-area' => array(__('Sandbox Area', 'fulltext-search')),
528 'wpfts-options-analytics' => array(__('Analytics', 'fulltext-search')),
529 //'wpfts-options-addons' => array(__('Addons', 'fulltext-search')),
530 'wpfts-options-support' => array(__('Support & Docs', 'fulltext-search')),
531 );
532 $ps1_start = $wpfts_core->get_option('ps1_start_dt');
533 if ((strlen($ps1_start) > 0) && ((strtotime($ps1_start) + 24 * 3600 * 14) < current_time('timestamp'))) {
534 $menu_items['wpfts-options-ps'] = array(__('Partnership', 'fulltext-search'));
535 }
536
537 $menu_items = apply_filters('wpfts_admin_menu_items', $menu_items);
538
539 $matches = array();
540 $is_set_prefix = false;
541 foreach ($menu_items as $k => $d) {
542 $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');
543 if ((substr($tt, 0, 8) != 'toplevel') && (!$is_set_prefix)) {
544 if (preg_match('~^(.+_wpfts\-options).*~u', $tt, $matches)) {
545 $is_set_prefix = true;
546 $wpfts_core->SetPrefixScreen($matches[1]);
547 }
548 }
549 }
550
551 add_filter('plugin_action_links', 'wpfts_settings_link', 10, 2);
552
553 do_action('wpfts_admin_menu');
554 }
555
556 function wpfts_enqueues($hook_suffix)
557 {
558 global $wpfts_core;
559
560 $version = (defined('WP_DEBUG') && WP_DEBUG) ? time() : WPFTS_VERSION;
561
562 $wpfts_core->set_is_settings_page();
563
564 wp_enqueue_style('wpfts_style', plugins_url('style/wpfts_main.css', __FILE__), array(), $version);
565 wp_enqueue_script('wpfts_script', plugins_url('js/wpfts_script.js', __FILE__), array(), $version);
566 wp_enqueue_script('wpfts_jsonview', plugins_url('js/jsonview.js', __FILE__), array(), $version);
567
568 if ($wpfts_core->is_wpfts_settings_page) {
569
570 wp_enqueue_style('wpfts_style_bs', plugins_url('style/bs_wpfts.css', __FILE__), array(), $version);
571 wp_enqueue_style('wpfts_style_ui', plugins_url('style/ui_main.css', __FILE__), array(), $version);
572 wp_enqueue_style('wpfts_style_fa', plugins_url('style/fontawesome-all.css', __FILE__), array(), $version);
573 wp_enqueue_style('wpfts_style_s2', plugins_url('style/select2/select2.min.css', __FILE__), array(), $version);
574
575 wp_enqueue_script('wpfts_script_bs', plugins_url('js/bootstrap.min.js', __FILE__), array('jquery'), $version);
576 wp_enqueue_script('wpfts_script_ui', plugins_url('js/ui_main.js', __FILE__), array(), $version);
577 wp_enqueue_script('wpfts_script_s2', plugins_url('js/select2/select2.min.js', __FILE__), array(), $version);
578
579 wp_enqueue_script('wpfts_ace_script', plugins_url('classes/ace/ace.js', __FILE__), array('jquery'), $version);
580
581 // Remove welcome_message
582 $wpfts_core->set_option('is_welcome_message', '');
583
584 wp_enqueue_style('wp-pointer');
585
586 wp_enqueue_script('postbox');
587 wp_enqueue_script('wp-pointer');
588 }
589
590 do_action('wpfts_admin_scripts');
591 }
592
593 function wpfts_settings_link($links, $file)
594 {
595 $this_plugin = dirname(plugin_basename(dirname(__FILE__))) . '/fulltext-search.php';
596 if ($file == $this_plugin) {
597 $links[] = '<a href="admin.php?page=wpfts-options">' . __('Settings', 'fulltext-search' ) . '</a>';
598 }
599 return $links;
600 }
601
602 function wpfts_option_page()
603 {
604 global $wpfts_core;
605
606 if (!current_user_can('manage_options')) {
607 wp_die(esc_html(__('Sorry, but you do not have permissions to change settings.', 'fulltext-search')));
608 }
609
610 /* Make sure post was from this page */
611 if (isset($_POST) && (count($_POST) > 0)) {
612 check_admin_referer('wpfts-options');
613 }
614
615 $wpfts_core->set_option('is_welcome_message', '');
616
617 require dirname(__FILE__).'/admin/admin_page.php';
618 }
619
620 function WPFTS_Get_Widget_List()
621 {
622 global $wpfts_core;
623
624 if ($wpfts_core && is_object($wpfts_core) && (is_a($wpfts_core, 'WPFTS_Core'))) {
625 return $wpfts_core->GetWidgetPresets();
626 }
627
628 return array();
629 }
630
631 /**
632 * Called when any post/page/etc updated or created
633 *
634 * We need to reindex the post by this action
635 */
636 function wpfts_save_post_action($post_id)
637 {
638 wpfts_post_reindex($post_id);
639 }
640 add_action('save_post', 'wpfts_save_post_action', 99);
641
642 /**
643 * Called when any post/page/etc was deleted
644 *
645 * We need to delete the post from the index by this action
646 */
647 function wpfts_deleted_post_action($post_id)
648 {
649 wpfts_post_reindex($post_id);
650 }
651 add_action('after_delete_post', 'wpfts_deleted_post_action', 99);
652
653 function wpfts_post_reindex($post_id, $is_force_remove = false, $is_raw_cache_remove = false)
654 {
655 global $wpfts_core;
656
657 if ($is_raw_cache_remove) {
658 $wpfts_core->removeRawCache($post_id);
659 }
660
661 // First, let's force sync
662 $wpfts_core->MakePostsSync(true);
663
664 // Make some magic to force this post indexed first
665 $q = 'update `wpftsi_index` set force_rebuild = 2 where tid = "'.addslashes($post_id).'" and tsrc = "wp_posts"';
666 $wpfts_core->db->query($q);
667
668 // Force status recalculation
669 $wpfts_core->set_option('status_next_ts', 0);
670
671 // Break current loop to start over
672 $wpfts_core->set_option('is_break_loop', 1);
673
674 // Ensure loop is starting
675 $wpfts_core->CallIndexerStartNoBlocking();
676
677 /*
678 $res = $wpfts_core->reindex_post($post_id, $is_force_remove);
679
680 if (!$res) {
681 trigger_error('Error reindex post ID='.$post_id.': '.$wpfts_core->index_error, E_USER_NOTICE);
682 return false;
683 }
684 */
685
686 return true;
687 }
688
689 function wpfts_set_pause($is_on = true, $is_start_indexer = false)
690 {
691 global $wpfts_core;
692
693 if ($wpfts_core) {
694 return $wpfts_core->SetPause($is_on, $is_start_indexer);
695 }
696
697 return false;
698 }
699
700 /** Smart Excerpts filters */
701 add_filter('the_title', function($out)
702 {
703 global $wpfts_core;
704
705 if ($wpfts_core && is_a($wpfts_core, 'WPFTS_Core')) {
706 $is_smart_excerpts = intval($wpfts_core->get_option('is_smart_excerpts'));
707 if ($is_smart_excerpts != 0) {
708
709 $loop_or_block = in_the_loop();
710 if (!$loop_or_block) {
711 if (class_exists('WP_Block_Supports')) {
712 if (isset(WP_Block_Supports::$block_to_render['blockName'])) {
713 $bn = WP_Block_Supports::$block_to_render['blockName'];
714 if (preg_match('~\/post\-title$~', $bn)) {
715 $loop_or_block = true;
716 }
717 }
718 }
719 }
720
721 if ((is_search() && !is_admin() && $loop_or_block) || ($wpfts_core->forced_se_query !== false)) {
722 $post = get_post();
723 $ri = new WPFTS_Result_Item(0, $post);
724 return $ri->TitleText($out);
725 }
726 }
727 }
728
729 return $out;
730 });
731
732 add_filter('attachment_link', function($link, $post_id)
733 {
734 global $wpfts_core;
735
736 if ($wpfts_core && is_a($wpfts_core, 'WPFTS_Core')) {
737 $is_smart_excerpts = intval($wpfts_core->get_option('is_smart_excerpts'));
738 if ($is_smart_excerpts != 0) {
739
740 $loop_or_block = in_the_loop();
741 if (!$loop_or_block) {
742 if (class_exists('WP_Block_Supports')) {
743 if (isset(WP_Block_Supports::$block_to_render['blockName'])) {
744 $bn = WP_Block_Supports::$block_to_render['blockName'];
745 if (preg_match('~\/post\-title$~', $bn)) {
746 $loop_or_block = true;
747 }
748 }
749 }
750 }
751
752 if ((is_search() && !is_admin() && $loop_or_block) || ($wpfts_core->forced_se_query !== false)) {
753 $ri = new WPFTS_Result_Item($post_id);
754 return $ri->TitleLink($link);
755 }
756 }
757 }
758
759 return $link;
760 }, 10, 2);
761
762 add_filter('page_link', function($link, $post_id, $leavename)
763 {
764 global $wpfts_core;
765
766 if ($wpfts_core && is_a($wpfts_core, 'WPFTS_Core')) {
767 $is_smart_excerpts = intval($wpfts_core->get_option('is_smart_excerpts'));
768 if ($is_smart_excerpts != 0) {
769
770 $loop_or_block = in_the_loop();
771 if (!$loop_or_block) {
772 if (class_exists('WP_Block_Supports')) {
773 if (isset(WP_Block_Supports::$block_to_render['blockName'])) {
774 $bn = WP_Block_Supports::$block_to_render['blockName'];
775 if (preg_match('~\/post\-title$~', $bn)) {
776 $loop_or_block = true;
777 }
778 }
779 }
780 }
781
782 if ((is_search() && !is_admin() && $loop_or_block) || ($wpfts_core->forced_se_query !== false)) {
783 $ri = new WPFTS_Result_Item($post_id);
784 return $ri->TitleLink($link);
785 }
786 }
787 }
788
789 return $link;
790 }, 10, 3);
791
792 add_filter('post_type_link', function($link, $post, $leavename)
793 {
794 global $wpfts_core;
795
796 if ($wpfts_core && is_a($wpfts_core, 'WPFTS_Core')) {
797 $is_smart_excerpts = intval($wpfts_core->get_option('is_smart_excerpts'));
798 if ($is_smart_excerpts != 0) {
799
800 $loop_or_block = in_the_loop();
801 if (!$loop_or_block) {
802 if (class_exists('WP_Block_Supports')) {
803 if (isset(WP_Block_Supports::$block_to_render['blockName'])) {
804 $bn = WP_Block_Supports::$block_to_render['blockName'];
805 if (preg_match('~\/post\-title$~', $bn)) {
806 $loop_or_block = true;
807 }
808 }
809 }
810 }
811
812 if ((is_search() && !is_admin() && $loop_or_block) || ($wpfts_core->forced_se_query !== false)) {
813 $ri = new WPFTS_Result_Item(0, $post);
814 return $ri->TitleLink($link);
815 }
816 }
817 }
818
819 return $link;
820 }, 10, 3);
821
822 add_filter('post_link', function($link, $post, $leavename)
823 {
824 global $wpfts_core;
825
826 if ($wpfts_core && is_a($wpfts_core, 'WPFTS_Core')) {
827 $is_smart_excerpts = intval($wpfts_core->get_option('is_smart_excerpts'));
828 if ($is_smart_excerpts != 0) {
829
830 $loop_or_block = in_the_loop();
831 if (!$loop_or_block) {
832 if (class_exists('WP_Block_Supports')) {
833 if (isset(WP_Block_Supports::$block_to_render['blockName'])) {
834 $bn = WP_Block_Supports::$block_to_render['blockName'];
835 if (preg_match('~\/post\-title$~', $bn)) {
836 $loop_or_block = true;
837 }
838 }
839 }
840 }
841
842 if ((is_search() && !is_admin() && $loop_or_block) || ($wpfts_core->forced_se_query !== false)) {
843 $ri = new WPFTS_Result_Item(0, $post);
844 return $ri->TitleLink($link);
845 }
846 }
847 }
848
849 return $link;
850 }, 10, 3);
851
852 add_filter('get_the_excerpt', function($out)
853 {
854 global $wpfts_core;
855
856 if ($wpfts_core && is_a($wpfts_core, 'WPFTS_Core')) {
857
858 $is_smart_excerpts = intval($wpfts_core->get_option('is_smart_excerpts'));
859 if ($is_smart_excerpts != 0) {
860
861 $post = get_post();
862
863 $loop_or_block = in_the_loop();
864 if (!$loop_or_block) {
865 if (class_exists('WP_Block_Supports')) {
866 if (isset(WP_Block_Supports::$block_to_render['blockName'])) {
867 $bn = WP_Block_Supports::$block_to_render['blockName'];
868 if (preg_match('~\/post\-excerpt$~', $bn)) {
869 $loop_or_block = true;
870 }
871 }
872 }
873 }
874
875 if (is_search() && !is_admin() && $loop_or_block) {
876
877 $ri = new WPFTS_Result_Item(0, $post);
878 $query = get_search_query(false);
879 $out = '<div class="wpfts-result-item">'.$ri->Excerpt($query).'</div>';
880 return $out;
881 } elseif ($wpfts_core->forced_se_query !== false) {
882 $ri = new WPFTS_Result_Item(0, $post);
883 $query = $wpfts_core->forced_se_query;
884 $out = '<div class="wpfts-result-item">'.$ri->Excerpt($query).'</div>';
885 return $out;
886 } else {
887 // Leave excerpt unchanged
888 }
889 }
890 }
891
892 return $out;
893 });
894
895 /**
896 * Convert HTML "<" and ">" and also quotes to unicode entities to prevent XSS attacks
897 */
898 function wpfts_json_encode($data)
899 {
900 return wp_json_encode($data, JSON_HEX_TAG | JSON_HEX_QUOT);
901 }
902