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

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