From dff641e7b361fdb3366990f2dabba97acbb7cd9b Mon Sep 17 00:00:00 2001 From: Ajay D'Souza Date: Thu, 12 Sep 2024 21:22:25 +0100 Subject: [PATCH] Files updated * Updated Settings_API * Renamed Better_Search to Better_Search_Core_Query --- includes/admin/settings/class-metabox-api.php | 54 +++----- .../admin/settings/class-settings-api.php | 115 ++++++++++++---- .../admin/settings/class-settings-form.php | 130 +++++++++++------- .../settings/class-settings-sanitize.php | 114 +++++++++++++-- includes/admin/settings/js/admin-scripts.js | 73 ---------- .../admin/settings/js/admin-scripts.min.js | 1 - .../settings/js/settings-admin-scripts.js | 70 ++++++++++ .../settings/js/settings-admin-scripts.min.js | 1 + .../admin/settings/js/taxonomy-suggest.js | 2 +- ...php => class-better-search-core-query.php} | 4 +- includes/class-better-search-query.php | 2 +- includes/class-main.php | 84 ++++++++++- 12 files changed, 447 insertions(+), 203 deletions(-) delete mode 100644 includes/admin/settings/js/admin-scripts.js delete mode 100644 includes/admin/settings/js/admin-scripts.min.js create mode 100644 includes/admin/settings/js/settings-admin-scripts.js create mode 100644 includes/admin/settings/js/settings-admin-scripts.min.js rename includes/{class-better-search.php => class-better-search-core-query.php} (99%) diff --git a/includes/admin/settings/class-metabox-api.php b/includes/admin/settings/class-metabox-api.php index bb26dea..d7fa061 100644 --- a/includes/admin/settings/class-metabox-api.php +++ b/includes/admin/settings/class-metabox-api.php @@ -2,8 +2,7 @@ /** * Class to display and save a Metabox. * - * @link https://webberzone.com - * @since 2.0.0 + * @since 3.3.0 * * @package WebberZone\Better_Search */ @@ -18,8 +17,9 @@ /** * ATA Metabox class to register the metabox for ata_snippets post type. * - * @since 2.0.0 + * @since 3.5.0 */ +#[\AllowDynamicProperties] class Metabox_API { /** @@ -27,7 +27,7 @@ class Metabox_API { * * @var string */ - const VERSION = '2.2.0'; + const VERSION = '2.3.0'; /** * Settings Key. @@ -77,10 +77,11 @@ class Metabox_API { * @param array|string $args { * Array or string of arguments. Default is blank array. * - * @type string $settings_key Admin menu type. See add_custom_menu_page() for options. - * @type string $prefix Parent menu slug. - * @type string $post_type Admin menu slug. - * @type array $registered_settings Settings fields array. + * @type string $settings_key Settings key - is used to prepare the form fields. It is not the meta key. + * @type string $prefix Used to create the meta keys. The meta key format is _{$prefix}_{$setting_id}. + * @type string|array|\WP_Screen $post_type The post type(s) on which to show the box. + * @type array $registered_settings Settings fields array. + * @type string $checkbox_modified_text Text to show to indicate a checkbox has been modified from its default value. * } */ public function __construct( $args ) { @@ -99,9 +100,9 @@ public function __construct( $args ) { $this->$name = $value; } + add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) ); add_action( 'add_meta_boxes', array( $this, 'add_meta_boxes' ) ); add_action( "save_post_{$this->post_type}", array( $this, 'save' ) ); - add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) ); } /** @@ -154,34 +155,11 @@ public static function enqueue_scripts_styles() { ) ); - wp_enqueue_script( - 'wz-admin-js', - plugins_url( 'js/admin-scripts' . $minimize . '.js', __FILE__ ), - array( 'jquery' ), - self::VERSION, - true - ); - wp_enqueue_script( - 'wz-codemirror-js', - plugins_url( 'js/apply-codemirror' . $minimize . '.js', __FILE__ ), - array( 'jquery' ), - self::VERSION, - true - ); - wp_enqueue_script( - 'wz-taxonomy-suggest-js', - plugins_url( 'js/taxonomy-suggest' . $minimize . '.js', __FILE__ ), - array( 'jquery' ), - self::VERSION, - true - ); - wp_enqueue_script( - 'wz-media-selector-js', - plugins_url( 'js/media-selector' . $minimize . '.js', __FILE__ ), - array( 'jquery' ), - self::VERSION, - true - ); + // Enqueue WZ Admin JS. + wp_enqueue_script( 'wz-admin-js' ); + wp_enqueue_script( 'wz-codemirror-js' ); + wp_enqueue_script( 'wz-taxonomy-suggest-js' ); + wp_enqueue_script( 'wz-media-selector-js' ); } /** @@ -363,7 +341,7 @@ public function sanitize_post_meta( $settings ) { } } $settings[ $fields['ids_field'] ] = join( ',', $ids ); - $settings[ $key ] = \WebberZone\Better_Search\Util\Helpers::str_putcsv( $names ); + $settings[ $key ] = Settings_Sanitize::str_putcsv( $names ); } else { $settings[ $fields['ids_field'] ] = ''; } diff --git a/includes/admin/settings/class-settings-api.php b/includes/admin/settings/class-settings-api.php index b42f8f9..a26aed0 100644 --- a/includes/admin/settings/class-settings-api.php +++ b/includes/admin/settings/class-settings-api.php @@ -6,7 +6,7 @@ * Portions of this code have been inspired by Easy Digital Downloads, WordPress Settings Sandbox, WordPress Settings API class, etc. * * @link https://webberzone.com - * @since 1.7.0 + * @since 3.3.0 * * @package WebberZone\Better_Search */ @@ -21,8 +21,9 @@ /** * Settings API wrapper class * - * @version 2.3.0 + * @version 2.5.1 */ +#[\AllowDynamicProperties] class Settings_API { /** @@ -30,7 +31,7 @@ class Settings_API { * * @var string */ - const VERSION = '2.3.0'; + const VERSION = '2.5.2'; /** * Settings Key. @@ -332,7 +333,7 @@ public function add_custom_menu_page( $menu ) { 'parent_slug' => 'options-general.php', 'page_title' => '', 'menu_title' => '', - 'capability' => 'manage_options', + 'capability' => $this->get_capability_for_menu(), 'menu_slug' => '', 'function' => array( $this, 'plugin_settings' ), @@ -415,6 +416,42 @@ public function admin_menu() { add_action( 'load-' . $this->settings_page, array( $this, 'settings_help' ) ); } + /** + * Get the appropriate capability for the menu based on the user's roles and settings. + * + * @param array $roles Array of roles to check. + * @param string $base_capability The default capability. + * @param \WP_User $current_user The current user object. + * @param array $role_capabilities Array of role capabilities. + * @return string The capability to use for the menu. + */ + public static function get_capability_for_menu( $roles = array(), $base_capability = 'manage_options', $current_user = null, $role_capabilities = array() ) { + if ( ! $current_user ) { + $current_user = wp_get_current_user(); + } + + if ( empty( $roles ) || in_array( 'administrator', $current_user->roles, true ) ) { + return $base_capability; + } + + if ( empty( $role_capabilities ) ) { + $role_capabilities = array( + 'editor' => 'edit_others_posts', + 'author' => 'publish_posts', + 'contributor' => 'edit_posts', + 'subscriber' => 'read', + ); + } + + foreach ( $current_user->roles as $role ) { + if ( in_array( $role, $roles, true ) && isset( $role_capabilities[ $role ] ) ) { + return $role_capabilities[ $role ]; + } + } + + return $base_capability; + } + /** * Enqueue scripts and styles. * @@ -422,6 +459,38 @@ public function admin_menu() { */ public function admin_enqueue_scripts( $hook ) { + $minimize = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '' : '.min'; + + // Settings API scripts. + wp_register_script( + 'wz-admin-js', + plugins_url( 'js/settings-admin-scripts' . $minimize . '.js', __FILE__ ), + array( 'jquery' ), + self::VERSION, + true + ); + wp_register_script( + 'wz-codemirror-js', + plugins_url( 'js/apply-codemirror' . $minimize . '.js', __FILE__ ), + array( 'jquery' ), + self::VERSION, + true + ); + wp_register_script( + 'wz-taxonomy-suggest-js', + plugins_url( 'js/taxonomy-suggest' . $minimize . '.js', __FILE__ ), + array( 'jquery' ), + self::VERSION, + true + ); + wp_register_script( + 'wz-media-selector-js', + plugins_url( 'js/media-selector' . $minimize . '.js', __FILE__ ), + array( 'jquery' ), + self::VERSION, + true + ); + if ( $hook === $this->settings_page ) { self::enqueue_scripts_styles(); } @@ -432,8 +501,6 @@ public function admin_enqueue_scripts( $hook ) { */ public static function enqueue_scripts_styles() { - $minimize = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '' : '.min'; - wp_enqueue_style( 'wp-color-picker' ); wp_enqueue_media(); @@ -452,27 +519,9 @@ public static function enqueue_scripts_styles() { ) ); - wp_enqueue_script( - 'wz-admin-js', - plugins_url( 'js/admin-scripts' . $minimize . '.js', __FILE__ ), - array( 'jquery' ), - self::VERSION, - true - ); - wp_enqueue_script( - 'wz-codemirror-js', - plugins_url( 'js/apply-codemirror' . $minimize . '.js', __FILE__ ), - array( 'jquery' ), - self::VERSION, - true - ); - wp_enqueue_script( - 'wz-taxonomy-suggest-js', - plugins_url( 'js/taxonomy-suggest' . $minimize . '.js', __FILE__ ), - array( 'jquery' ), - self::VERSION, - true - ); + wp_enqueue_script( 'wz-admin-js' ); + wp_enqueue_script( 'wz-codemirror-js' ); + wp_enqueue_script( 'wz-taxonomy-suggest-js' ); } /** @@ -527,6 +576,7 @@ public function admin_init() { 'field_class' => '', 'field_attributes' => '', 'placeholder' => '', + 'pro' => false, ) ); @@ -547,7 +597,14 @@ public function admin_init() { } // Register the settings into the options table. - register_setting( $settings_key, $settings_key, array( $this, 'settings_sanitize' ) ); + register_setting( + $settings_key, + $settings_key, + array( + 'sanitize_callback' => array( $this, 'settings_sanitize' ), + 'show_in_rest' => true, + ) + ); } /** @@ -787,7 +844,7 @@ public function plugin_settings() { ?>

translation_strings['page_header'] ); ?>

- prefix . '_settings_page_header' ); ?> + prefix . '_settings_page_header' ); ?>
diff --git a/includes/admin/settings/class-settings-form.php b/includes/admin/settings/class-settings-form.php index 761d5e2..f8be4f3 100644 --- a/includes/admin/settings/class-settings-form.php +++ b/includes/admin/settings/class-settings-form.php @@ -3,7 +3,7 @@ * Generates the settings form. * * @link https://webberzone.com - * @since 2.0.0 + * @since 3.3.0 * * @package WebberZone\Better_Search */ @@ -17,6 +17,8 @@ /** * Generates the settings form. + * + * @version 2.5.0 */ class Settings_Form { @@ -159,7 +161,7 @@ public function callback_text( $args ) { $size = sanitize_html_class( isset( $args['size'] ) ? $args['size'] : 'regular' ); $class = sanitize_html_class( $args['field_class'] ); $placeholder = empty( $args['placeholder'] ) ? '' : ' placeholder="' . $args['placeholder'] . '"'; - $disabled = ! empty( $args['disabled'] ) ? ' disabled="disabled"' : ''; + $disabled = ( ! empty( $args['disabled'] ) || $args['pro'] ) ? ' disabled="disabled"' : ''; $readonly = ( isset( $args['readonly'] ) && true === $args['readonly'] ) ? ' readonly="readonly"' : ''; $attributes = $disabled . $readonly; @@ -235,15 +237,21 @@ public function callback_postids( $args ) { */ public function callback_textarea( $args ) { - $value = isset( $args['value'] ) ? $args['value'] : $this->get_option( $args['id'], $args['options'] ); - $class = sanitize_html_class( $args['field_class'] ); + $value = isset( $args['value'] ) ? $args['value'] : $this->get_option( $args['id'], $args['options'] ); + $class = sanitize_html_class( $args['field_class'] ); + $placeholder = empty( $args['placeholder'] ) ? '' : ' placeholder="' . $args['placeholder'] . '"'; + $disabled = ( ! empty( $args['disabled'] ) || $args['pro'] ) ? ' disabled="disabled"' : ''; + $readonly = ( isset( $args['readonly'] ) && true === $args['readonly'] ) ? ' readonly="readonly"' : ''; + $attributes = $disabled . $readonly; $html = sprintf( - '', + '', $this->settings_key, sanitize_key( $args['id'] ), esc_textarea( stripslashes( $value ) ), - 'large-text ' . $class + 'large-text ' . $class, + $attributes, + $placeholder ); $html .= $this->get_field_description( $args ); @@ -279,13 +287,24 @@ public function callback_html( $args ) { */ public function callback_checkbox( $args ) { - $value = isset( $args['value'] ) ? $args['value'] : $this->get_option( $args['id'], $args['options'] ); - $checked = ! empty( $value ) ? checked( 1, $value, false ) : ''; - $default = isset( $args['options'] ) ? (int) $args['options'] : ''; + $value = isset( $args['value'] ) ? $args['value'] : $this->get_option( $args['id'], $args['options'] ); + $checked = ! empty( $value ) ? checked( 1, $value, false ) : ''; + $default = isset( $args['options'] ) ? (int) $args['options'] : ''; + $disabled = ( ! empty( $args['disabled'] ) || $args['pro'] ) ? ' disabled="disabled"' : ''; - $html = sprintf( '', $this->settings_key, sanitize_key( $args['id'] ) ); - $html .= sprintf( '', $this->settings_key, sanitize_key( $args['id'] ), $checked ); - $html .= ( (bool) $value !== (bool) $default ) ? '' . $this->checkbox_modified_text . '' : ''; + $html = sprintf( + '', + $this->settings_key, + sanitize_key( $args['id'] ) + ); + $html .= sprintf( + '', + $this->settings_key, + sanitize_key( $args['id'] ), + $checked, + $disabled + ); + $html .= ( (bool) $value !== (bool) $default ) ? '' . $this->checkbox_modified_text . '' : ''; $html .= $this->get_field_description( $args ); /** This filter has been defined in class-settings-api.php */ @@ -303,25 +322,28 @@ public function callback_checkbox( $args ) { public function callback_multicheck( $args ) { $html = ''; - $value = isset( $args['value'] ) ? $args['value'] : $this->get_option( $args['id'], $args['options'] ); + $value = isset( $args['value'] ) ? $args['value'] : $this->get_option( $args['id'], $args['default'] ); + $value_array = wp_parse_list( $value ); + $disabled = ( ! empty( $args['disabled'] ) || $args['pro'] ) ? ' disabled="disabled"' : ''; if ( ! empty( $args['options'] ) ) { - $html .= sprintf( '', $this->settings_key, $args['id'] ); + $html .= sprintf( '', $this->settings_key, sanitize_key( $args['id'] ) ); foreach ( $args['options'] as $key => $option ) { - if ( isset( $value[ $key ] ) ) { + if ( in_array( $key, $value_array, true ) ) { $enabled = $key; } else { $enabled = null; } $html .= sprintf( - ' ', + ' ', $this->settings_key, sanitize_key( $args['id'] ), sanitize_key( $key ), esc_attr( $key ), - checked( $key, $enabled, false ) + checked( $key, $enabled, false ), + $disabled ); $html .= sprintf( '
', @@ -331,9 +353,8 @@ public function callback_multicheck( $args ) { $option ); } - - $html .= $this->get_field_description( $args ); } + $html .= $this->get_field_description( $args ); /** This filter has been defined in class-settings-api.php */ echo apply_filters( $this->prefix . '_after_setting_output', $html, $args ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped @@ -350,15 +371,17 @@ public function callback_multicheck( $args ) { public function callback_radio( $args ) { $html = ''; - $value = isset( $args['value'] ) ? $args['value'] : $this->get_option( $args['id'], $args['default'] ); + $value = isset( $args['value'] ) ? $args['value'] : $this->get_option( $args['id'], $args['default'] ); + $disabled = ( ! empty( $args['disabled'] ) || $args['pro'] ) ? ' disabled="disabled"' : ''; foreach ( $args['options'] as $key => $option ) { $html .= sprintf( - ' ', + ' ', $this->settings_key, sanitize_key( $args['id'] ), $key, - checked( $value, $key, false ) + checked( $value, $key, false ), + $disabled ); $html .= sprintf( '
', @@ -386,25 +409,28 @@ public function callback_radio( $args ) { public function callback_radiodesc( $args ) { $html = ''; - $value = isset( $args['value'] ) ? $args['value'] : $this->get_option( $args['id'], $args['default'] ); + $value = isset( $args['value'] ) ? $args['value'] : $this->get_option( $args['id'], $args['default'] ); + $disabled = ( ! empty( $args['disabled'] ) || $args['pro'] ) ? ' disabled="disabled"' : ''; foreach ( $args['options'] as $option ) { $html .= sprintf( - ' ', + ' ', $this->settings_key, sanitize_key( $args['id'] ), $option['id'], - checked( $value, $option['id'], false ) + checked( $value, $option['id'], false ), + $disabled ); $html .= sprintf( - '', + '', $this->settings_key, sanitize_key( $args['id'] ), $option['id'], - $option['name'] + $option['name'], + wp_kses_post( $option['description'] ) ); - $html .= ': ' . wp_kses_post( $option['description'] ) . '
'; + $html .= '
'; } $html .= $this->get_field_description( $args ); @@ -477,9 +503,10 @@ public function callback_number( $args ) { $step = isset( $args['step'] ) ? intval( $args['step'] ) : 1; $size = isset( $args['size'] ) ? $args['size'] : 'regular'; $placeholder = empty( $args['placeholder'] ) ? '' : ' placeholder="' . esc_attr( $args['placeholder'] ) . '"'; + $disabled = ( ! empty( $args['disabled'] ) || $args['pro'] ) ? ' disabled="disabled"' : ''; $html = sprintf( - '', + '', esc_attr( (string) $step ), esc_attr( (string) $max ), esc_attr( (string) $min ), @@ -487,7 +514,8 @@ public function callback_number( $args ) { sanitize_key( $args['id'] ), esc_attr( stripslashes( $value ) ), $placeholder, - $this->settings_key + $this->settings_key, + $disabled ); $html .= $this->get_field_description( $args ); @@ -539,7 +567,8 @@ public function callback_select( $args ) { public function callback_posttypes( $args ) { $html = ''; - $options = isset( $args['value'] ) ? $args['value'] : $this->get_option( $args['id'], $args['options'] ); + $options = isset( $args['value'] ) ? $args['value'] : $this->get_option( $args['id'], $args['options'] ); + $disabled = ( ! empty( $args['disabled'] ) || $args['pro'] ) ? ' disabled="disabled"' : ''; // If post_types contains a query string then parse it with wp_parse_args. if ( is_string( $options ) && strpos( $options, '=' ) ) { @@ -548,23 +577,32 @@ public function callback_posttypes( $args ) { $post_types = wp_parse_list( $options ); } - $wp_post_types = get_post_types( + $wp_post_types = get_post_types( array( 'public' => true, - ) + ), + 'objects' + ); + + $posts_types_inc = array_intersect( wp_list_pluck( $wp_post_types, 'name' ), $post_types ); + + $html .= sprintf( + '', + $this->settings_key, + sanitize_key( $args['id'] ) ); - $posts_types_inc = array_intersect( $wp_post_types, $post_types ); foreach ( $wp_post_types as $wp_post_type ) { $html .= sprintf( - ' ', + '
', sanitize_key( $args['id'] ), - esc_attr( $wp_post_type ), - checked( true, in_array( $wp_post_type, $posts_types_inc, true ), false ), - $this->settings_key + esc_attr( $wp_post_type->name ), + checked( true, in_array( $wp_post_type->name, $posts_types_inc, true ), false ), + $this->settings_key, + $wp_post_type->label, + $disabled ); - $html .= sprintf( '
', sanitize_key( $args['id'] ), $wp_post_type, $this->settings_key ); } @@ -603,21 +641,17 @@ public function callback_taxonomies( $args ) { $taxonomies_inc = array_intersect( wp_list_pluck( (array) $wp_taxonomies, 'name' ), $taxonomies ); + $html .= sprintf( '', $this->settings_key, sanitize_key( $args['id'] ) ); + foreach ( $wp_taxonomies as $wp_taxonomy ) { $html .= sprintf( - ' ', + '
', sanitize_key( $args['id'] ), esc_attr( $wp_taxonomy->name ), checked( true, in_array( $wp_taxonomy->name, $taxonomies_inc, true ), false ), - $this->settings_key - ); - $html .= sprintf( - '
', - sanitize_key( $args['id'] ), - esc_attr( $wp_taxonomy->name ), - $wp_taxonomy->labels->name, - $this->settings_key + $this->settings_key, + $wp_taxonomy->labels->name ); } diff --git a/includes/admin/settings/class-settings-sanitize.php b/includes/admin/settings/class-settings-sanitize.php index c3f5838..d30c49c 100644 --- a/includes/admin/settings/class-settings-sanitize.php +++ b/includes/admin/settings/class-settings-sanitize.php @@ -152,28 +152,36 @@ public function sanitize_checkbox_field( $value ) { return $value; } + /** + * Sanitize multicheck fields + * + * @param array|int $value The field value. + * @return string $value Sanitized value + */ + public function sanitize_multicheck_field( $value ) { + $values = ( -1 === (int) $value ) ? array() : array_map( 'sanitize_text_field', (array) wp_unslash( $value ) ); + + return implode( ',', $values ); + } + /** * Sanitize post_types fields * - * @param array $value The field value. + * @param array|int $value The field value. * @return string $value Sanitized value */ public function sanitize_posttypes_field( $value ) { - $post_types = array_map( 'sanitize_text_field', (array) wp_unslash( $value ) ); - - return implode( ',', $post_types ); + return $this->sanitize_multicheck_field( $value ); } /** * Sanitize post_types fields * - * @param array $value The field value. + * @param array|int $value The field value. * @return string $value Sanitized value */ public function sanitize_taxonomies_field( $value ) { - $taxonomies = array_map( 'sanitize_text_field', (array) wp_unslash( $value ) ); - - return implode( ',', $taxonomies ); + return $this->sanitize_multicheck_field( $value ); } /** @@ -185,4 +193,94 @@ public function sanitize_taxonomies_field( $value ) { public function sanitize_color_field( $value ) { return sanitize_hex_color( $value ); } + + /** + * Convert a string to CSV. + * + * @param array $input_array Input string. + * @param string $delimiter Delimiter. + * @param string $enclosure Enclosure. + * @param string $terminator Terminating string. + * @return string CSV string. + */ + public static function str_putcsv( $input_array, $delimiter = ',', $enclosure = '"', $terminator = "\n" ) { + // First convert associative array to numeric indexed array. + $work_array = array(); + foreach ( $input_array as $key => $value ) { + $work_array[] = $value; + } + + $output = ''; + $array_size = count( $work_array ); + + for ( $i = 0; $i < $array_size; $i++ ) { + // Nested array, process nest item. + if ( is_array( $work_array[ $i ] ) ) { + $output .= self::str_putcsv( $work_array[ $i ], $delimiter, $enclosure, $terminator ); + } else { + switch ( gettype( $work_array[ $i ] ) ) { + // Manually set some strings. + case 'NULL': + $sp_format = ''; + break; + case 'boolean': + $sp_format = ( true === $work_array[ $i ] ) ? 'true' : 'false'; + break; + // Make sure sprintf has a good datatype to work with. + case 'integer': + $sp_format = '%i'; + break; + case 'double': + $sp_format = '%0.2f'; + break; + case 'string': + $sp_format = '%s'; + $work_array[ $i ] = str_replace( "$enclosure", "$enclosure$enclosure", $work_array[ $i ] ); + break; + // Unknown or invalid items for a csv - note: the datatype of array is already handled above, assuming the data is nested. + case 'object': + case 'resource': + default: + $sp_format = ''; + break; + } + $output .= sprintf( '%2$s' . $sp_format . '%2$s', $work_array[ $i ], $enclosure ); + $output .= ( $i < ( $array_size - 1 ) ) ? $delimiter : $terminator; + } + } + + return $output; + } + + /** + * Processes category/taxonomy slugs and adds a new element to the settings array containing the term taxonomy IDs. + * + * @param array $settings The settings array containing the taxonomy slugs to sanitize. + * @param string $source_key The key in the settings array containing the slugs. Pattern is Name (taxonomy:term_taxonomy_id). + * @param string $target_key The key in the settings array to store the sanitized term taxonomy IDs. + * @return void + */ + public static function sanitize_tax_slugs( &$settings, $source_key, $target_key ) { + if ( isset( $settings[ $source_key ] ) ) { + $slugs = array_unique( str_getcsv( $settings[ $source_key ] ) ); + + foreach ( $slugs as $slug ) { + // Pattern is Name (taxonomy:term_taxonomy_id). + preg_match( '/(.*)\((.*):(\d+)\)/i', (string) $slug, $matches ); + if ( isset( $matches[3] ) ) { + $term = get_term_by( 'term_taxonomy_id', $matches[3] ); + } else { + // Fallback to fetching the category as this was the original format. + $term = get_term_by( 'name', $slug, 'category' ); + } + if ( isset( $term->term_taxonomy_id ) ) { + $tax_ids[] = $term->term_taxonomy_id; + $tax_slugs[] = "{$term->name} ({$term->taxonomy}:{$term->term_taxonomy_id})"; + } + } + + $settings[ $target_key ] = isset( $tax_ids ) ? join( ',', $tax_ids ) : ''; + $settings[ $source_key ] = isset( $tax_slugs ) ? self::str_putcsv( $tax_slugs ) : ''; + } + } } diff --git a/includes/admin/settings/js/admin-scripts.js b/includes/admin/settings/js/admin-scripts.js deleted file mode 100644 index 9c25d89..0000000 --- a/includes/admin/settings/js/admin-scripts.js +++ /dev/null @@ -1,73 +0,0 @@ -jQuery(document).ready(function($) { - // File browser. - $('.file-browser').on('click', function (event) { - event.preventDefault(); - - var self = $(this); - - // Create the media frame. - var file_frame = wp.media.frames.file_frame = wp.media({ - title: self.data('uploader_title'), - button: { - text: self.data('uploader_button_text'), - }, - multiple: false - }); - - file_frame.on('select', function () { - attachment = file_frame.state().get('selection').first().toJSON(); - self.prev('.file-url').val(attachment.url).change(); - }); - - // Finally, open the modal - file_frame.open(); - }); - - // Prompt the user when they leave the page without saving the form. - var formmodified=0; - - function confirmFormChange() { - formmodified=1; - } - - function confirmExit() { - if ( formmodified == 1 ) { - return true; - } - } - - function formNotModified() { - formmodified = 0; - } - - $('form *').change( confirmFormChange ); - - window.onbeforeunload = confirmExit; - - $( "input[name='submit']" ).click(formNotModified); - $( "input[id='search-submit']" ).click(formNotModified); - $( "input[id='doaction']" ).click(formNotModified); - $( "input[id='doaction2']" ).click(formNotModified); - $( "input[name='filter_action']" ).click(formNotModified); - - $( function() { - $( "#post-body-content" ).tabs({ - create: function( event, ui ) { - $( ui.tab.find("a") ).addClass( "nav-tab-active" ); - }, - activate: function( event, ui ) { - $( ui.oldTab.find("a") ).removeClass( "nav-tab-active" ); - $( ui.newTab.find("a") ).addClass( "nav-tab-active" ); - } - }); - }); - - // Initialise ColorPicker. - $( '.color-field' ).each( function ( i, element ) { - $( element ).wpColorPicker(); - }); - - $('.reset-default-thumb').click(function(){ - document.getElementById("tptn_settings[thumb_default]").value = tptn_admin.thumb_default; - }); -}); diff --git a/includes/admin/settings/js/admin-scripts.min.js b/includes/admin/settings/js/admin-scripts.min.js deleted file mode 100644 index 8ed6fb4..0000000 --- a/includes/admin/settings/js/admin-scripts.min.js +++ /dev/null @@ -1 +0,0 @@ -jQuery(document).ready((function(t){t(".file-browser").on("click",(function(e){e.preventDefault();var n=t(this),a=wp.media.frames.file_frame=wp.media({title:n.data("uploader_title"),button:{text:n.data("uploader_button_text")},multiple:!1});a.on("select",(function(){attachment=a.state().get("selection").first().toJSON(),n.prev(".file-url").val(attachment.url).change()})),a.open()}));var e=0;function n(){e=0}t("form *").change((function(){e=1})),window.onbeforeunload=function(){if(1==e)return!0},t("input[name='submit']").click(n),t("input[id='search-submit']").click(n),t("input[id='doaction']").click(n),t("input[id='doaction2']").click(n),t("input[name='filter_action']").click(n),t((function(){t("#post-body-content").tabs({create:function(e,n){t(n.tab.find("a")).addClass("nav-tab-active")},activate:function(e,n){t(n.oldTab.find("a")).removeClass("nav-tab-active"),t(n.newTab.find("a")).addClass("nav-tab-active")}})})),t(".color-field").each((function(e,n){t(n).wpColorPicker()})),t(".reset-default-thumb").click((function(){document.getElementById("tptn_settings[thumb_default]").value=tptn_admin.thumb_default}))})); \ No newline at end of file diff --git a/includes/admin/settings/js/settings-admin-scripts.js b/includes/admin/settings/js/settings-admin-scripts.js new file mode 100644 index 0000000..775339a --- /dev/null +++ b/includes/admin/settings/js/settings-admin-scripts.js @@ -0,0 +1,70 @@ +jQuery(document).ready(function ($) { + // File browser. + $('.file-browser').on('click', function (event) { + event.preventDefault(); + + var self = $(this); + + // Create the media frame. + var file_frame = wp.media.frames.file_frame = wp.media({ + title: self.data('uploader_title'), + button: { + text: self.data('uploader_button_text'), + }, + multiple: false + }); + + file_frame.on('select', function () { + attachment = file_frame.state().get('selection').first().toJSON(); + self.prev('.file-url').val(attachment.url).change(); + }); + + // Finally, open the modal + file_frame.open(); + }); + + // Prompt the user when they leave the page without saving the form. + var formmodified = 0; + + function confirmFormChange() { + formmodified = 1; + } + + function confirmExit() { + if (formmodified == 1) { + return true; + } + } + + function formNotModified() { + formmodified = 0; + } + + $('form').on('change', 'input, textarea, select', confirmFormChange); + + window.onbeforeunload = confirmExit; + + $('input[name="submit"], input#search-submit, input#doaction, input#doaction2, input[name="filter_action"]').on('click', formNotModified); + + $(function () { + $("#post-body-content").tabs({ + create: function (event, ui) { + $(ui.tab.find("a")).addClass("nav-tab-active"); + }, + activate: function (event, ui) { + $(ui.oldTab.find("a")).removeClass("nav-tab-active"); + $(ui.newTab.find("a")).addClass("nav-tab-active"); + } + }); + }); + + // Initialise ColorPicker. + $('.color-field').each(function (i, element) { + $(element).wpColorPicker(); + }); + + $('.reset-default-thumb').on('click', function () { + $('#tptn_settings\\[thumb_default\\]').val(tptn_admin.thumb_default); + }); + +}); diff --git a/includes/admin/settings/js/settings-admin-scripts.min.js b/includes/admin/settings/js/settings-admin-scripts.min.js new file mode 100644 index 0000000..61fa906 --- /dev/null +++ b/includes/admin/settings/js/settings-admin-scripts.min.js @@ -0,0 +1 @@ +jQuery(document).ready(function(t){function n(){i=1}function e(){if(1==i)return!0}function a(){i=0}t(".file-browser").on("click",function(n){n.preventDefault();var e=t(this),a=wp.media.frames.file_frame=wp.media({title:e.data("uploader_title"),button:{text:e.data("uploader_button_text")},multiple:!1});a.on("select",function(){attachment=a.state().get("selection").first().toJSON(),e.prev(".file-url").val(attachment.url).change()}),a.open()});var i=0;t("form").on("change","input, textarea, select",n),window.onbeforeunload=e,t('input[name="submit"], input#search-submit, input#doaction, input#doaction2, input[name="filter_action"]').on("click",a),t(function(){t("#post-body-content").tabs({create:function(n,e){t(e.tab.find("a")).addClass("nav-tab-active")},activate:function(n,e){t(e.oldTab.find("a")).removeClass("nav-tab-active"),t(e.newTab.find("a")).addClass("nav-tab-active")}})}),t(".color-field").each(function(n,e){t(e).wpColorPicker()}),t(".reset-default-thumb").on("click",function(){t("#tptn_settings\\[thumb_default\\]").val(tptn_admin.thumb_default)})}); \ No newline at end of file diff --git a/includes/admin/settings/js/taxonomy-suggest.js b/includes/admin/settings/js/taxonomy-suggest.js index 31a07a1..c5a9eb9 100644 --- a/includes/admin/settings/js/taxonomy-suggest.js +++ b/includes/admin/settings/js/taxonomy-suggest.js @@ -8,7 +8,7 @@ jQuery(document).ready(function($) { options = options || {}; var taxonomy = options.taxonomy || $element.attr( 'data-wp-taxonomy' ) || 'category'; - var tag_search = options.tag_search || $element.attr( 'data-wp-action' ) || 'ata_tag_search'; + var tag_search = options.tag_search || $element.attr( 'data-wp-action' ) || 'wz_tags_search'; delete( options.taxonomy ); delete( options.tag_search ); diff --git a/includes/class-better-search.php b/includes/class-better-search-core-query.php similarity index 99% rename from includes/class-better-search.php rename to includes/class-better-search-core-query.php index 6e27368..44a4be4 100644 --- a/includes/class-better-search.php +++ b/includes/class-better-search-core-query.php @@ -21,7 +21,7 @@ * * @since 3.0.0 */ - class Better_Search { + class Better_Search_Core_Query { /** * Blog ID. @@ -879,8 +879,6 @@ public function posts_pre_query( $posts, $query ) { 'posts_per_page' => $query->get( 'posts_per_page' ), ) ); - $posts = array_map( 'get_post', $posts ); - // Set the score for each of the posts. if ( $posts ) { foreach ( $posts as $post ) { diff --git a/includes/class-better-search-query.php b/includes/class-better-search-query.php index a5979e7..6bfc764 100644 --- a/includes/class-better-search-query.php +++ b/includes/class-better-search-query.php @@ -28,7 +28,7 @@ class Better_Search_Query extends WP_Query { * @param array|string $args The Query variables. Accepts an array or a query string. */ public function __construct( $args = array() ) { - $better_search = new Better_Search( $args ); + $better_search = new Better_Search_Core_Query( $args ); add_filter( 'pre_get_posts', array( $better_search, 'pre_get_posts' ), 10 ); add_filter( 'posts_fields', array( $better_search, 'posts_fields' ), 10, 2 ); diff --git a/includes/class-main.php b/includes/class-main.php index 712674c..743675e 100644 --- a/includes/class-main.php +++ b/includes/class-main.php @@ -7,6 +7,9 @@ namespace WebberZone\Better_Search; +use Better_Search_Core_Query; +use WebberZone\Better_Search\Admin\Activator; + if ( ! defined( 'WPINC' ) ) { exit; } @@ -163,7 +166,7 @@ public function register_widgets() { */ public function load_seamless_mode( $query ) { if ( $query->is_search() && bsearch_get_option( 'seamless' ) ) { - new \Better_Search(); + new \Better_Search_Core_Query( $query->query_vars ); } } @@ -273,4 +276,83 @@ public static function document_title( $title ) { return $title; } + + /** + * Hook into WP_Query to check if bsearch_query is set and is true. If so, we load the Top 10 query. + * + * @since 3.5.0 + * + * @param \WP_Query $query The WP_Query object. + */ + public function parse_query( $query ) { + if ( true === $query->get( 'better_search_query' ) ) { + new Better_Search_Core_Query( $query->query_vars ); + } + } + + /** + * Checks if another version of Top 10/Top 10 Pro is active and deactivates it. + * Hooked on `activated_plugin` so other plugin is deactivated when current plugin is activated. + * + * @since 3.5.0 + * + * @param string $plugin The plugin being activated. + * @param bool $network_wide Whether the plugin is being activated network-wide. + */ + public function activated_plugin( $plugin, $network_wide ) { + if ( ! in_array( $plugin, array( 'better-search/better-search.php', 'better-search-pro/better-search.php' ), true ) ) { + return; + } + + Activator::activation_hook( $network_wide ); + + $plugin_to_deactivate = 'better-search/better-search.php'; + $deactivated_notice_id = '1'; + + // If we just activated the free version, deactivate the pro version. + if ( $plugin === $plugin_to_deactivate ) { + $plugin_to_deactivate = 'better-search-pro/better-search.php'; + $deactivated_notice_id = '2'; + } + + if ( is_multisite() && is_network_admin() ) { + $active_plugins = (array) get_site_option( 'active_sitewide_plugins', array() ); + $active_plugins = array_keys( $active_plugins ); + } else { + $active_plugins = (array) get_option( 'active_plugins', array() ); + } + + foreach ( $active_plugins as $plugin_basename ) { + if ( $plugin_to_deactivate === $plugin_basename ) { + set_transient( 'bsearch_deactivated_notice_id', $deactivated_notice_id, 1 * HOUR_IN_SECONDS ); + deactivate_plugins( $plugin_basename ); + return; + } + } + } + + /** + * Displays a notice when either Top 10 or Top 10 Pro is automatically deactivated. + * + * @since 3.5.0 + */ + public function plugin_deactivated_notice() { + $deactivated_notice_id = (int) get_transient( 'bsearch_deactivated_notice_id' ); + if ( ! in_array( $deactivated_notice_id, array( 1, 2 ), true ) ) { + return; + } + + $message = __( "Top 10 and Top 10 Pro should not be active at the same time. We've automatically deactivated Top 10.", 'better-search' ); + if ( 2 === $deactivated_notice_id ) { + $message = __( "Top 10 and Top 10 Pro should not be active at the same time. We've automatically deactivated Top 10 Pro.", 'better-search' ); + } + + ?> +
+

+
+