Skip to content

Commit eac2d30

Browse files
committed
chore: Sync includes from pro version
- Copy updated includes folder from better-search-pro - Remove pro subfolder - Remove Freemius premium-only initialization blocks - Update translation files
1 parent 2adf5ad commit eac2d30

6 files changed

Lines changed: 567 additions & 392 deletions

File tree

includes/admin/class-settings.php

Lines changed: 166 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ public function __construct() {
7777
Hook_Registry::add_filter( self::$prefix . '_settings_sanitize', array( $this, 'change_settings_on_save' ), 99 );
7878
Hook_Registry::add_filter( self::$prefix . '_after_setting_output', array( $this, 'after_setting_output' ), 10, 2 );
7979
Hook_Registry::add_action( self::$prefix . '_settings_form_buttons', array( $this, 'add_wizard_button' ) );
80+
81+
Hook_Registry::add_action( 'wp_ajax_nopriv_' . self::$prefix . '_taxonomy_search_tom_select', array( __CLASS__, 'taxonomy_search_tom_select' ) );
82+
Hook_Registry::add_action( 'wp_ajax_' . self::$prefix . '_taxonomy_search_tom_select', array( __CLASS__, 'taxonomy_search_tom_select' ) );
8083
}
8184

8285
/**
@@ -603,14 +606,12 @@ public static function settings_search() {
603606
'exclude_cat_slugs' => array(
604607
'id' => 'exclude_cat_slugs',
605608
'name' => esc_html__( 'Exclude Categories', 'better-search' ),
606-
'desc' => esc_html__( 'Comma separated list of category slugs. The field above has an autocomplete so simply start typing in the starting letters and it will prompt you with options. Does not support custom taxonomies.', 'better-search' ),
609+
'desc' => esc_html__( 'The field above has an autocomplete. Start typing in the starting letters, and it will prompt you with options. This field requires a specific format as displayed by the autocomplete.', 'better-search' ),
607610
'type' => 'csv',
608611
'default' => '',
609612
'size' => 'large',
610-
'field_class' => 'category_autocomplete',
611-
'field_attributes' => array(
612-
'data-wp-taxonomy' => 'category',
613-
),
613+
'field_class' => 'ts_autocomplete',
614+
'field_attributes' => self::get_taxonomy_search_field_attributes( 'category' ),
614615
),
615616
'exclude_categories' => array(
616617
'id' => 'exclude_categories',
@@ -1227,4 +1228,164 @@ public function add_wizard_button() {
12271228
esc_html__( 'Start Settings Wizard', 'better-search' )
12281229
);
12291230
}
1231+
1232+
/**
1233+
* AJAX handler for Tom Select taxonomy search.
1234+
*
1235+
* @since 4.2.0
1236+
*
1237+
* @return void
1238+
*/
1239+
public static function taxonomy_search_tom_select() {
1240+
// Verify nonce.
1241+
if ( ! isset( $_REQUEST['nonce'] ) ) {
1242+
wp_send_json_error( array( 'message' => 'Missing nonce' ) );
1243+
}
1244+
1245+
$nonce_valid = wp_verify_nonce( sanitize_key( $_REQUEST['nonce'] ), self::$prefix . '_taxonomy_search_tom_select' );
1246+
1247+
if ( ! $nonce_valid ) {
1248+
wp_send_json_error(
1249+
array(
1250+
'message' => 'Invalid nonce',
1251+
'received_nonce' => sanitize_key( $_REQUEST['nonce'] ),
1252+
'expected_action' => self::$prefix . '_taxonomy_search_tom_select',
1253+
)
1254+
);
1255+
}
1256+
1257+
if ( ! isset( $_REQUEST['endpoint'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
1258+
wp_send_json_error( 'Missing endpoint' );
1259+
}
1260+
1261+
$endpoint = sanitize_key( $_REQUEST['endpoint'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
1262+
1263+
$search_term = isset( $_REQUEST['q'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['q'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
1264+
1265+
$comma = _x( ',', 'tag delimiter', 'better-search' );
1266+
if ( ',' !== $comma ) {
1267+
$search_term = str_replace( $comma, ',', $search_term );
1268+
}
1269+
if ( false !== strpos( $search_term, ',' ) ) {
1270+
$search_term = explode( ',', $search_term );
1271+
$search_term = $search_term[ count( $search_term ) - 1 ];
1272+
}
1273+
$search_term = trim( $search_term );
1274+
1275+
if ( 'public_taxonomies' === $endpoint ) {
1276+
$taxonomies = (array) get_taxonomies( array( 'public' => true ), 'objects' );
1277+
$taxonomy = array();
1278+
$tax = null;
1279+
1280+
foreach ( $taxonomies as $taxonomy_name => $taxonomy_object ) {
1281+
if ( ! is_string( $taxonomy_name ) || '' === $taxonomy_name ) {
1282+
continue;
1283+
}
1284+
1285+
if ( empty( $taxonomy_object->cap->assign_terms ) ) {
1286+
continue;
1287+
}
1288+
1289+
if ( ! current_user_can( $taxonomy_object->cap->assign_terms ) ) {
1290+
continue;
1291+
}
1292+
1293+
$taxonomy[] = $taxonomy_name;
1294+
}
1295+
1296+
if ( empty( $taxonomy ) ) {
1297+
wp_send_json_success( array() );
1298+
}
1299+
1300+
$tax = get_taxonomy( $taxonomy[0] );
1301+
} else {
1302+
$taxonomy = $endpoint;
1303+
$tax = get_taxonomy( $taxonomy );
1304+
1305+
if ( ! $tax ) {
1306+
wp_send_json_error( 'Invalid taxonomy' );
1307+
}
1308+
1309+
if ( ! current_user_can( $tax->cap->assign_terms ) ) {
1310+
wp_send_json_error( 'Insufficient permissions' );
1311+
}
1312+
}
1313+
1314+
/** This filter has been defined in /wp-admin/includes/ajax-actions.php */
1315+
$term_search_min_chars = (int) apply_filters( 'term_search_min_chars', 2, $tax, $search_term );
1316+
1317+
/*
1318+
* Require $term_search_min_chars chars for matching (default: 2)
1319+
* ensure it's a non-negative, non-zero integer.
1320+
*/
1321+
if ( ( 0 === $term_search_min_chars ) || ( strlen( $search_term ) < $term_search_min_chars ) ) {
1322+
wp_send_json_success( array() );
1323+
}
1324+
1325+
$terms = get_terms(
1326+
array(
1327+
'taxonomy' => $taxonomy,
1328+
'name__like' => $search_term,
1329+
'hide_empty' => false,
1330+
)
1331+
);
1332+
1333+
$results = array();
1334+
foreach ( (array) $terms as $term ) {
1335+
$formatted_string = "{$term->name} ({$term->taxonomy}:{$term->term_taxonomy_id})";
1336+
$results[] = array(
1337+
'value' => $formatted_string,
1338+
'text' => $term->name,
1339+
);
1340+
}
1341+
1342+
wp_send_json_success( $results );
1343+
}
1344+
1345+
/**
1346+
* Get field attributes for Tom Select taxonomy search fields.
1347+
*
1348+
* @since 4.2.0
1349+
*
1350+
* @param string $taxonomy The taxonomy to search.
1351+
* @param array $ts_config Optional Tom Select configuration.
1352+
* @return array Field attributes array.
1353+
*/
1354+
private static function get_taxonomy_search_field_attributes( $taxonomy, $ts_config = array() ) {
1355+
$attributes = array(
1356+
'data-wp-prefix' => strtoupper( (string) self::$prefix ),
1357+
'data-wp-action' => self::$prefix . '_taxonomy_search_tom_select',
1358+
'data-wp-nonce' => wp_create_nonce( self::$prefix . '_taxonomy_search_tom_select' ),
1359+
'data-wp-endpoint' => $taxonomy,
1360+
);
1361+
1362+
if ( ! empty( $ts_config ) ) {
1363+
$attributes['data-wp-ts-config'] = wp_json_encode( $ts_config );
1364+
}
1365+
1366+
return $attributes;
1367+
}
1368+
1369+
/**
1370+
* Get field attributes for Tom Select meta key search fields.
1371+
*
1372+
* @since 4.2.0
1373+
*
1374+
* @param array $ts_config Optional Tom Select configuration.
1375+
* @return array Field attributes array.
1376+
*/
1377+
private static function get_meta_keys_search_field_attributes( $ts_config = array() ) {
1378+
$attributes = array(
1379+
'data-wp-prefix' => strtoupper( (string) self::$prefix ),
1380+
'data-wp-action' => self::$prefix . '_taxonomy_search_tom_select',
1381+
'data-wp-nonce' => wp_create_nonce( self::$prefix . '_taxonomy_search_tom_select' ),
1382+
'data-wp-endpoint' => 'meta_keys',
1383+
);
1384+
1385+
if ( ! empty( $ts_config ) ) {
1386+
$attributes['data-ts-config'] = wp_json_encode( $ts_config );
1387+
}
1388+
1389+
return $attributes;
1390+
}
12301391
}

includes/admin/settings/class-settings-wizard-api.php

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ class Settings_Wizard_API {
126126
* @type array $translation_strings Translation strings.
127127
* @type string $page_slug Wizard page slug.
128128
* @type array $menu_args Menu arguments array with parent and capability.
129+
* @type bool $hide_when_completed Whether to hide the wizard submenu item after completion.
129130
* }
130131
*/
131132
public function __construct( $settings_key, $prefix, $args = array() ) {
@@ -138,6 +139,7 @@ public function __construct( $settings_key, $prefix, $args = array() ) {
138139
'translation_strings' => array(),
139140
'admin_menu_position' => 999,
140141
'page_slug' => "{$prefix}_wizard",
142+
'hide_when_completed' => true,
141143
'menu_args' => array(
142144
'parent' => '', // Empty for dashboard, or parent slug for submenu.
143145
'capability' => 'manage_options',
@@ -223,13 +225,38 @@ public function admin_menu() {
223225
$parent = ! empty( $this->menu_args['parent'] ) ? $this->menu_args['parent'] : 'index.php';
224226

225227
$this->page_id = add_submenu_page(
226-
$this->is_wizard_completed() ? 'options.php' : $parent,
227-
$this->translation_strings['page_title'],
228-
$this->translation_strings['menu_title'],
228+
$parent,
229+
(string) $this->translation_strings['page_title'],
230+
(string) $this->translation_strings['menu_title'],
229231
$capability,
230232
$this->page_slug,
231233
array( $this, 'render_wizard_page' )
232234
);
235+
236+
$hide_when_completed = isset( $this->args['hide_when_completed'] ) ? (bool) $this->args['hide_when_completed'] : true;
237+
if ( $hide_when_completed && $this->is_wizard_completed() ) {
238+
add_action( 'admin_head', array( $this, 'hide_completed_wizard_submenu' ) );
239+
}
240+
}
241+
242+
/**
243+
* Hide wizard submenu item when the wizard is completed.
244+
*
245+
* @return void
246+
*/
247+
public function hide_completed_wizard_submenu() {
248+
if ( ! $this->is_wizard_completed() ) {
249+
return;
250+
}
251+
$slug = sanitize_key( $this->page_slug );
252+
?>
253+
<style>
254+
#adminmenu a[href$="page=<?php echo esc_attr( $slug ); ?>"],
255+
#adminmenu a[href*="page=<?php echo esc_attr( $slug ); ?>&"] {
256+
display: none;
257+
}
258+
</style>
259+
<?php
233260
}
234261

235262
/**
@@ -444,12 +471,14 @@ protected function previous_step() {
444471
* @param int $step Step number to redirect to.
445472
*/
446473
protected function redirect_to_step( $step ) {
447-
$url = add_query_arg(
474+
$parent = ! empty( $this->menu_args['parent'] ) ? $this->menu_args['parent'] : 'admin.php';
475+
$base = admin_url( $parent );
476+
$url = add_query_arg(
448477
array(
449478
'page' => $this->page_slug,
450479
'step' => $step,
451480
),
452-
admin_url( 'admin.php' )
481+
$base
453482
);
454483
wp_safe_redirect( $url );
455484
exit;
@@ -872,12 +901,14 @@ protected function render_wizard_steps_navigation() {
872901
* @return string Step URL.
873902
*/
874903
protected function get_step_url( $step ) {
904+
$parent = ! empty( $this->menu_args['parent'] ) ? $this->menu_args['parent'] : 'admin.php';
905+
$base = admin_url( $parent );
875906
return add_query_arg(
876907
array(
877908
'page' => $this->page_slug,
878909
'step' => $step,
879910
),
880-
admin_url( 'admin.php' )
911+
$base
881912
);
882913
}
883914

includes/admin/settings/js/settings-admin-scripts.js

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -26,33 +26,6 @@ jQuery(document).ready(function ($) {
2626
file_frame.open();
2727
});
2828

29-
// Prompt the user when they leave the page without saving the form.
30-
var formmodified = 0;
31-
32-
function confirmFormChange() {
33-
formmodified = 1;
34-
}
35-
36-
function confirmExit() {
37-
if (formmodified == 1) {
38-
return true;
39-
}
40-
}
41-
42-
function formNotModified() {
43-
formmodified = 0;
44-
}
45-
46-
// Only apply form change detection to settings form, not wizard or other forms
47-
$('#' + prefix + '-settings-form').on('change', 'input, textarea, select', confirmFormChange);
48-
49-
// Only set window.onbeforeunload if we're on the settings page
50-
if ($('#' + prefix + '-settings-form').length) {
51-
window.onbeforeunload = confirmExit;
52-
}
53-
54-
$('input[name="submit"], input#search-submit, input#doaction, input#doaction2, input[name="filter_action"]').on('click', formNotModified);
55-
5629
$(function () {
5730
$("#post-body-content").tabs({
5831
create: function (event, ui) {

includes/admin/settings/js/settings-admin-scripts.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)