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

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