Below is a differential between the unpatched vulnerable code and the patched update, for reference.
--- a/search-analytics/admin/admin.php
+++ b/search-analytics/admin/admin.php
@@ -8,6 +8,7 @@
public function __construct() {
$this->includes();
$this->add_actions_and_filters();
+ $this->init_menus_and_screens();
}
private function includes() {
@@ -16,6 +17,7 @@
include_once( 'includes/class.charts.php' );
include_once( 'includes/class.stats.php' );
include_once( 'includes/class.export-csv.php' );
+ include_once( 'includes/class.menu.php' );
}
public function add_actions_and_filters() {
@@ -23,8 +25,16 @@
add_filter( 'plugin_row_meta', array( 'MWTSA_Dashboard', 'add_plugin_meta_links' ), 10, 2 );
}
+
+ public function init_menus_and_screens()
+ {
+ $stats = new MWTSA_Admin_Stats();
+ $settings = new MWTSA_Admin_Settings();
+
+ new MWTSA_Admin_Menu( $stats, $settings );
+ }
}
}
-return new MWTSA_Admin();
No newline at end of file
+new MWTSA_Admin();
--- a/search-analytics/admin/includes/class.charts.php
+++ b/search-analytics/admin/includes/class.charts.php
@@ -16,7 +16,7 @@
public function load_admin_assets( $hook ) {
- if ( $hook == 'dashboard_page_search-analytics/admin/includes/class.stats' ) {
+ if ( $hook == 'dashboard_page_mwtsa-search-analytics' ) {
wp_enqueue_script( 'mwtsa-chart-bundle-script', MWTSAI()->plugin_admin_url . 'assets/js/chart.bundle.min.js', array( 'jquery' ), MWTSAI()->version, true );
wp_enqueue_script( 'mwtsa-chart-controller-script', MWTSAI()->plugin_admin_url . 'assets/js/chart-controller.js', array( 'mwtsa-chart-bundle-script' ), MWTSAI()->version, true );
@@ -35,56 +35,56 @@
}
public function render_stats_chart() {
- if ( empty( $_REQUEST['search-term'] ) && empty ( MWTSA_Options::get_option( 'mwtsa_hide_charts' ) ) ) : // phpcs:ignore WordPress.Security.NonceVerification.Recommended
- $default_line_style = MWTSA_Options::get_option( 'chart_default_line_style' );
- $default_range = MWTSA_Options::get_option( 'chart_default_range' );
-
- $line_options = array(
- 'basic' => __( 'Basic Line', 'search-analytics' ),
- 'stepped' => __( 'Stepped Line', 'search-analytics' )
- );
-
- $range_options = array(
- '2w' => __( '2 Weeks', 'search-analytics' ),
- '2wc' => __( '2 Weeks Comparison', 'search-analytics' ),
- '1m' => __( '1 Month', 'search-analytics' ),
- '1mc' => __( '1 Month Comparison', 'search-analytics' )
- );
- ?>
- <div class="col-content">
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+ if ( ! empty( $_REQUEST['search-term'] ) || ! empty( MWTSA_Options::get_option( 'mwtsa_hide_charts' ) ) ) {
+ return;
+ }
+
+ $default_line_style = MWTSA_Options::get_option( 'chart_default_line_style' );
+ $default_range = MWTSA_Options::get_option( 'chart_default_range' );
+
+ $line_options = array(
+ 'basic' => __( 'Basic Line', 'search-analytics' ),
+ 'stepped' => __( 'Stepped Line', 'search-analytics' )
+ );
+
+ $range_options = array(
+ '2w' => __( '2 Weeks', 'search-analytics' ),
+ '2wc' => __( '2 Weeks Comparison', 'search-analytics' ),
+ '1m' => __( '1 Month', 'search-analytics' ),
+ '1mc' => __( '1 Month Comparison', 'search-analytics' )
+ );
+ ?>
+ <div class="col-content">
+
+ <h2><?php esc_html_e( "Search Results Charts", 'search-analytics' ) ?></h2>
+ <div class="mwtsa-chart-options">
+ <label for="chart-type">
+ <select id="chart-type" onchange="loadCharts()">
+ <?php foreach ( $line_options as $value => $label ) : ?>
+ <option value="<?php echo esc_attr( $value ) ?>" <?php selected( $value, $default_line_style ) ?>><?php echo esc_html( $label ) ?></option>
+ <?php endforeach; ?>
+ </select>
+ </label>
+ <label for="chart-ranges">
+ <select id="chart-ranges" onchange="loadCharts()">
+ <?php foreach ( $range_options as $value => $label ) : ?>
+ <option value="<?php echo esc_attr( $value ) ?>" <?php selected( $value, $default_range ) ?>><?php echo esc_html( $label ) ?></option>
+ <?php endforeach; ?>
+ </select>
+ </label>
+ <span onclick="saveAsDefault()" class="button"><?php esc_html_e( 'Save as default', 'search-analytics' ) ?></span>
+ </div>
- <h2><?php esc_html_e( "Search Results Charts", 'search-analytics' ) ?></h2>
- <div class="mwtsa-chart-options">
- <label for="chart-type">
- <select id="chart-type" onchange="loadCharts()">
- <?php foreach ( $line_options as $value => $label ) : ?>
- <option value="<?php echo esc_attr( $value ) ?>" <?php selected( $value, $default_line_style ) ?>><?php echo esc_html( $label ) ?></option>
- <?php endforeach; ?>
- </select>
- </label>
- <label for="chart-ranges">
- <select id="chart-ranges" onchange="loadCharts()">
- <?php foreach ( $range_options as $value => $label ) : ?>
- <option value="<?php echo esc_attr( $value ) ?>" <?php selected( $value, $default_range ) ?>><?php echo esc_html( $label ) ?></option>
- <?php endforeach; ?>
- </select>
- </label>
- <span onclick="saveAsDefault()" class="button"><?php esc_html_e( 'Save as default', 'search-analytics' ) ?></span>
- </div>
-
- <div id="chart-content">
- <canvas id="mwtsa-stats-chart" width="400" height="100"></canvas>
- </div>
+ <div id="chart-content">
+ <canvas id="mwtsa-stats-chart" width="400" height="100"></canvas>
</div>
- <?php endif;
+ </div>
+ <?php
}
public function render_chart_data() {
- $nonce = isset( $_REQUEST['nonce'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['nonce'] ) ) : '';
-
- if ( empty( $nonce ) || ! wp_verify_nonce( $nonce, $this->nonce_action ) ) {
- wp_send_json_error( 'Bad Request!' );
- }
+ check_ajax_referer( $this->nonce_action );
$ranges = ! empty( $_REQUEST['chart_ranges'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['chart_ranges'] ) ) : '2w';
@@ -125,11 +125,7 @@
}
public function save_default_chart_settings() {
- $nonce = isset( $_REQUEST['nonce'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['nonce'] ) ) : '';
-
- if ( empty( $nonce ) || ! wp_verify_nonce( $nonce, $this->nonce_action ) ) {
- wp_send_json_error( 'Bad Request!' );
- }
+ check_ajax_referer( $this->nonce_action );
if ( empty( $_POST['line_style'] ) || empty( $_POST['chart_ranges'] ) ) {
wp_send_json_error( 'Bad Request!' );
--- a/search-analytics/admin/includes/class.dashboard.php
+++ b/search-analytics/admin/includes/class.dashboard.php
@@ -11,7 +11,7 @@
}
public function init() {
- $this_user_role = mwt_get_current_user_roles();
+ $this_user_role = mwtsa_get_current_user_roles();
$plugin_options = MWTSA_Options::get_options();
$accepted_user_roles = array_values( array_intersect( $this_user_role, $plugin_options['mwtsa_display_stats_for_role'] ) );
@@ -52,44 +52,50 @@
echo '<span class="stats-list-value">' . absint( $total_searches ) . '</span></li>';
echo '<li><span class="stats-list-label">' . esc_html__( "Most Searched Term:", 'search-analytics' ) . '</span>';
- echo '<span class="stats-list-value">' . esc_attr( $most_searched_term['term'] ) . '</span></li>';
+ echo '<span class="stats-list-value">' . esc_html( $most_searched_term['term'] ) . '</span></li>';
echo '<li><span class="stats-list-label">' . esc_html__( "Most Searched Term Count:", 'search-analytics' ) . '</span>';
- echo '<span class="stats-list-value">' . absint( $most_searched_term['count'] ) . '</span></li>';
+ echo '<span class="stats-list-value">' . ((int) $most_searched_term['count']) . '</span></li>';
echo '<li><span class="stats-list-label">' . esc_html__( "Last Searched Term:", 'search-analytics' ) . '</span>';
- echo '<span class="stats-list-value">' . esc_attr( $last_search_term['term'] ) . '</span></li>';
+ echo '<span class="stats-list-value">' . esc_html( $last_search_term['term'] ) . '</span></li>';
echo '<li><span class="stats-list-label">' . esc_html__( "Last Searched Date:", 'search-analytics' ) . '</span>';
- echo '<span class="stats-list-value">' . esc_attr( $last_search_term['last_search_date'] ) . '</span></li>';
+ echo '<span class="stats-list-value">' . esc_html( $last_search_term['last_search_date'] ) . '</span></li>';
echo '</ul>';
- }
-
- public static function add_plugin_meta_links( $meta_fields, $file ) {
- if ( $file == 'search-analytics/mwt-search-analytics.php' ) {
-
- $meta_fields[] = "<a href='" . MWTSA_WORDPRESS_URL . "' target='_blank'>" . esc_html__( 'Support Forum', 'search-analytics' ) . "</a>";
- $svg = "<svg xmlns='http://www.w3.org/2000/svg' width='15' height='15' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='feather feather-star'><polygon points='12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2'/></svg>";
- $stars = '<i class="mwtsa-rate-stars">';
+ $stats_url = admin_url( 'admin.php?page=mwtsa-search-analytics' );
- for ( $i = 1; $i <= 5; $i ++ ) {
- $stars .= '<a href="' . MWTSA_WORDPRESS_URL . '/reviews/?rate=' . $i . '#new-post" target="_blank">' . $svg . '</a>';
- }
-
- $stars .= '</i>';
+ echo '<a href="' . esc_url( $stats_url ) . '" class="button button-secondary mwtsa-widget-stats-link">' . esc_html__( 'View all stats', 'search-analytics' ) . '</a>';
+ }
- $meta_fields[] = $stars;
+ public static function add_plugin_meta_links( $meta_fields, $file ) {
+ if ( $file !== 'search-analytics/mwt-search-analytics.php' ) {
+ return $meta_fields;
+ }
+
+ $meta_fields[] = "<a href='" . MWTSA_WORDPRESS_SUPPORT_URL . "' target='_blank'>" . esc_html__( 'Support Forum', 'search-analytics' ) . "</a>";
+ $svg = "<svg xmlns='http://www.w3.org/2000/svg' width='15' height='15' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='feather feather-star'><polygon points='12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2'/></svg>";
+
+ $stars = '<i class="mwtsa-rate-stars">';
+
+ for ( $i = 1; $i <= 5; $i ++ ) {
+ $stars .= '<a href="' . MWTSA_WORDPRESS_SUPPORT_URL . '/reviews/?rate=' . $i . '#new-post" target="_blank">' . $svg . '</a>';
+ }
+
+ $stars .= '</i>';
+
+ $meta_fields[] = $stars;
+
+ echo "<style>"
+ . ".mwtsa-rate-stars{display:inline-block;color:#ffb900;position:relative;top:3px;}"
+ . ".mwtsa-rate-stars a {color:#ffb900;}"
+ . ".mwtsa-rate-stars a svg{fill:#ffb900;}"
+ . ".mwtsa-rate-stars a:hover svg{fill:#ffb900}"
+ . ".mwtsa-rate-stars a:hover ~ a svg {fill:none;}"
+ . "</style>";
- echo "<style>"
- . ".mwtsa-rate-stars{display:inline-block;color:#ffb900;position:relative;top:3px;}"
- . ".mwtsa-rate-stars a {color:#ffb900;}"
- . ".mwtsa-rate-stars a svg{fill:#ffb900;}"
- . ".mwtsa-rate-stars a:hover svg{fill:#ffb900}"
- . ".mwtsa-rate-stars a:hover ~ a svg {fill:none;}"
- . "</style>";
- }
return $meta_fields;
}
--- a/search-analytics/admin/includes/class.export-csv.php
+++ b/search-analytics/admin/includes/class.export-csv.php
@@ -30,7 +30,7 @@
fputcsv( $stream, $result );
}
- fclose( $stream );
+ fclose( $stream ); // phpcs:ignore
exit();
}
}
--- a/search-analytics/admin/includes/class.menu.php
+++ b/search-analytics/admin/includes/class.menu.php
@@ -0,0 +1,138 @@
+<?php
+defined( "ABSPATH" ) || exit;
+
+if ( ! class_exists( 'MWTSA_Admin_Menu' ) ) {
+
+ class MWTSA_Admin_Menu {
+
+ private $stats;
+ private $settings;
+ private $view;
+
+ public function __construct( MWTSA_Admin_Stats $stats, MWTSA_Admin_Settings $settings ) {
+ $this->stats = $stats;
+ $this->settings = $settings;
+
+ add_action( 'admin_menu', array( $this, 'register' ) );
+ add_action( 'init', array( $this, 'redirect_legacy_urls' ) );
+ }
+
+ public function register() {
+ $stats_roles = $this->get_stats_roles();
+ $settings_roles = $this->get_settings_roles();
+
+ if ( empty( $stats_roles ) && empty( $settings_roles ) ) {
+ return;
+ }
+
+ $capability = ! empty( $stats_roles ) ? $stats_roles[0] : $settings_roles[0];
+
+ $this->view = add_menu_page(
+ __( 'Search Analytics', 'search-analytics' ),
+ __( 'Search Analytics', 'search-analytics' ),
+ $capability,
+ 'mwtsa-search-analytics',
+ array( $this->stats, 'render_stats_page' ),
+ 'dashicons-analytics',
+ 81
+ );
+
+ $this->stats->set_view( $this->view );
+
+ if ( ! empty( $stats_roles ) ) {
+ add_submenu_page(
+ 'mwtsa-search-analytics',
+ __( 'Statistics', 'search-analytics' ),
+ __( 'Statistics', 'search-analytics' ),
+ $stats_roles[0],
+ 'mwtsa-search-analytics',
+ array( $this->stats, 'render_stats_page' )
+ );
+
+ add_action( "load-{$this->view}", array( $this->stats, 'add_screen_options' ) );
+ add_action( "load-{$this->view}", array( $this->stats, 'init_stats_table' ) );
+ }
+
+ if ( ! empty( $settings_roles ) ) {
+ add_submenu_page(
+ 'mwtsa-search-analytics',
+ __( 'MWT: Search Analytics', 'search-analytics' ),
+ __( 'Settings', 'search-analytics' ),
+ $settings_roles[0],
+ 'mwtsa-search-analytics-settings',
+ array( $this->settings, 'options_page' )
+ );
+ }
+
+ // Backward-compat: keep the old Dashboard entry visible and redirect to new location
+ if ( ! empty( $stats_roles ) ) {
+ add_submenu_page(
+ 'index.php',
+ __( 'Search Analytics', 'search-analytics' ),
+ __( 'Search Analytics', 'search-analytics' ),
+ $stats_roles[0],
+ 'mwtsa-search-analytics-old',
+ array( $this, 'redirect_to_stats' )
+ );
+ }
+
+ // Backward-compat: keep the old Settings entry visible and redirect to new location
+ if ( ! empty( $settings_roles ) ) {
+ add_options_page(
+ __( 'MWT: Search Analytics', 'search-analytics' ),
+ __( 'MWT: Search Analytics', 'search-analytics' ),
+ $settings_roles[0],
+ 'mwtsa-search-analytics-settings-old',
+ array( $this, 'redirect_to_settings' )
+ );
+ }
+ }
+
+ public function redirect_to_stats() {
+ wp_safe_redirect( admin_url( 'admin.php?page=mwtsa-search-analytics' ) );
+ exit;
+ }
+
+ public function redirect_to_settings() {
+ wp_safe_redirect( admin_url( 'admin.php?page=mwtsa-search-analytics-settings' ) );
+ exit;
+ }
+
+ public function redirect_legacy_urls() {
+ if ( ! is_admin() || ! isset( $_GET['page'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+ return;
+ }
+
+ $page = sanitize_text_field( wp_unslash( $_GET['page'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+ $script = isset( $_SERVER['PHP_SELF'] ) ? basename( sanitize_text_field( wp_unslash( $_SERVER['PHP_SELF'] ) ) ) : '';
+
+ if ( 'search-analytics/admin/includes/class.stats.php' === $page ) {
+ wp_safe_redirect( admin_url( 'admin.php?page=mwtsa-search-analytics' ) );
+ exit;
+ }
+
+ if ( 'mwtsa-search-analytics' === $page && 'index.php' === $script ) {
+ wp_safe_redirect( admin_url( 'admin.php?page=mwtsa-search-analytics' ) );
+ exit;
+ }
+
+ if ( 'search-analytics' === $page && 'options-general.php' === $script ) {
+ wp_safe_redirect( admin_url( 'admin.php?page=mwtsa-search-analytics-settings' ) );
+ exit;
+ }
+ }
+
+ private function get_stats_roles() {
+ $options = MWTSA_Options::get_options();
+ $user_roles = mwtsa_get_current_user_roles();
+ return array_values( array_intersect( $user_roles, $options['mwtsa_display_stats_for_role'] ) );
+ }
+
+ private function get_settings_roles() {
+ $options = MWTSA_Options::get_options();
+ $user_roles = mwtsa_get_current_user_roles();
+ return array_values( array_intersect( $user_roles, $options['mwtsa_display_settings_for_role'] ) );
+ }
+ }
+
+}
--- a/search-analytics/admin/includes/class.settings.php
+++ b/search-analytics/admin/includes/class.settings.php
@@ -10,30 +10,9 @@
public function __construct() {
$this->existing_options = MWTSA_Options::get_options();
- add_action( 'admin_menu', array( $this, 'add_admin_menu' ) );
add_action( 'admin_init', array( $this, 'mwtsa_settings_init' ) );
}
- public function add_admin_menu() {
-
- $this_user_role = mwt_get_current_user_roles();
-
- $accepted_user_roles = array_values( array_intersect( $this_user_role, $this->existing_options['mwtsa_display_settings_for_role'] ) );
-
- if ( ! isset( $this->existing_options['mwtsa_display_settings_for_role'] ) || ! empty( $accepted_user_roles ) ) {
-
- add_options_page(
- __( 'MWT: Search Analytics', 'search-analytics' ),
- __( 'MWT: Search Analytics', 'search-analytics' ),
- $accepted_user_roles[0], 'search-analytics', array(
- &$this,
- 'options_page'
- )
- );
-
- }
- }
-
public function mwtsa_settings_init() {
register_setting( 'mwtsa_general_options', MWTSAI()->main_option_name, array(
@@ -108,7 +87,7 @@
add_settings_section(
'mwtsa_display_options_sections',
__( 'General Settings', 'search-analytics' ),
- array( &$this, 'settings_section_callback' ),
+ '__return_false',
'mwtsa_general_options'
);
@@ -194,8 +173,6 @@
}
public function field_exclude_search_for_role_after_logout_render() {
- global $mwtsa;
-
if ( ! isset( $this->existing_options['mwtsa_exclude_search_for_role_after_logout'] ) ) {
$this->existing_options['mwtsa_exclude_search_for_role_after_logout'] = 0;
}
@@ -205,27 +182,26 @@
<input type='checkbox' name='mwtsa_settings[mwtsa_exclude_search_for_role_after_logout]' value='1' <?php checked( $this->existing_options['mwtsa_exclude_search_for_role_after_logout'], 1 ) ?> />
</label>
<br/>
- <strong><?php esc_attr_e( 'Note: this will set a cookie in the browser of the user who logged in and has one of the user roles checked above.<br />This needs to be treated by the site's GDPR terms in case it is active for public user roles ( e.g. Subscriber, Client )<br />The cookie name is: ', 'search-analytics' ) ?>
- <i><?php echo esc_attr( $mwtsa->cookie_name ) ?></i>
+ <strong><?php echo wp_kses_post( __( 'Note: this will set a cookie in the browser of the user who logged in and has one of the user roles checked above.<br />This needs to be treated by the site's GDPR terms in case it is active for public user roles (ex. Subscriber, Client)<br />The cookie name is: ', 'search-analytics' ) ) ?>
+ <i><?php echo esc_attr( MWTSAI()->cookie_name ) ?></i>
</strong>
<br/>
<?php
}
public function field_exclude_doubled_search_for_interval_render() {
- global $mwtsa;
-
if ( ! isset( $this->existing_options['mwtsa_exclude_doubled_search_for_interval'] ) ) {
$this->existing_options['mwtsa_exclude_doubled_search_for_interval'] = 0;
}
?>
+ <!--suppress HtmlFormInputWithoutLabel -->
<input type="number" min="0" name="mwtsa_settings[mwtsa_exclude_doubled_search_for_interval]" value="<?php echo (int) $this->existing_options['mwtsa_exclude_doubled_search_for_interval'] ?>"/>
- <span><?php esc_attr_e( '( Note: set to 0 or leave empty to disable it )', 'search-analytics' ) ?></span>
+ <span><?php esc_html_e( '( Note: set to 0 or leave empty to disable it )', 'search-analytics' ) ?></span>
<br/>
<strong>
- <?php esc_attr_e( 'Note: this will set a cookie in the browser of the user who made any kind of search on the website.<br />This needs to be treated by the site's GDPR terms in case it's value is a number larger than 0<br />The cookie name is: ', 'search-analytics' ) ?>
- <i><?php echo esc_attr( $mwtsa->cookie_name ) ?></i>
+ <?php echo wp_kses_post( __( 'Note: this will set a cookie in the browser of the user who made any kind of search on the website.<br />This needs to be treated by the site's GDPR terms in case it's value is a number larger than 0<br />The cookie name is: ', 'search-analytics' ) ) ?>
+ <i><?php echo esc_attr( MWTSAI()->cookie_name ) ?></i>
</strong>
<?php
}
@@ -235,15 +211,16 @@
$this->existing_options['mwtsa_exclude_searches_from_ip_addresses'] = '';
}
- $admin_ip = mwt_get_current_user_ip();
+ $admin_ip = mwtsa_get_current_user_ip();
?>
+ <!--suppress HtmlFormInputWithoutLabel -->
<input type="text" name="mwtsa_settings[mwtsa_exclude_searches_from_ip_addresses]" value="<?php echo esc_attr( $this->existing_options['mwtsa_exclude_searches_from_ip_addresses'] ) ?>" placeholder="eg. 127.0.0.1"/>
- <span><?php esc_attr_e( '( Note: separate IP values by comma )', 'search-analytics' ) ?></span>
+ <span><?php esc_html_e( '( Note: separate IP values by comma )', 'search-analytics' ) ?></span>
<br/>
<strong><?php
/* translators: %s: The user's IP Address */
- printf( esc_attr__( 'Your IP address is: %s', 'search-analytics' ), esc_attr( $admin_ip ) ) ?></strong>
+ printf( esc_html__( 'Your IP address is: %s', 'search-analytics' ), esc_attr( $admin_ip ) ) ?></strong>
<?php
}
@@ -253,8 +230,9 @@
$this->existing_options['mwtsa_minimum_characters'] = 0;
}
?>
+ <!--suppress HtmlFormInputWithoutLabel -->
<input type="number" min="0" name="mwtsa_settings[mwtsa_minimum_characters]" value="<?php echo (int) $this->existing_options['mwtsa_minimum_characters'] ?>"/>
- <span><?php esc_attr_e( '( Note: set to 0 or leave empty to disable it )', 'search-analytics' ) ?></span>
+ <span><?php esc_html_e( '( Note: set to 0 or leave empty to disable it )', 'search-analytics' ) ?></span>
<br/>
<?php
}
@@ -266,8 +244,9 @@
}
?>
+ <!--suppress HtmlFormInputWithoutLabel -->
<input type="text" name="mwtsa_settings[mwtsa_exclude_if_string_contains]" value="<?php echo esc_attr( $this->existing_options['mwtsa_exclude_if_string_contains'] ); ?>" placeholder="eg. text, another one"/>
- <span><?php esc_attr_e( '( Note: enter comma (,) separated strings )', 'search-analytics' ) ?></span>
+ <span><?php esc_html_e( '( Note: enter comma (,) separated strings )', 'search-analytics' ) ?></span>
<?php
}
@@ -278,8 +257,9 @@
}
?>
+ <!--suppress HtmlFormInputWithoutLabel -->
<input type="text" name="mwtsa_settings[mwtsa_custom_search_url_params]" value="<?php echo esc_attr( $this->existing_options['mwtsa_custom_search_url_params'] ); ?>" placeholder="eg. wpv_post_search"/>
- <span><?php esc_attr_e( '( Note: enter comma (,) separated strings )', 'search-analytics' ) ?></span>
+ <span><?php esc_html_e( '( Note: enter comma (,) separated strings )', 'search-analytics' ) ?></span>
<?php
}
@@ -331,7 +311,7 @@
<label>
<input type="hidden" name='mwtsa_settings[mwtsa_uninstall]' value='0'/>
<input type='checkbox' name='mwtsa_settings[mwtsa_uninstall]' value='1' <?php checked( $this->existing_options['mwtsa_uninstall'], 1 ) ?> />
- <span><?php esc_attr_e( 'Remove plugin tables on uninstall', 'search-analytics' ) ?></span>
+ <span><?php esc_html_e( 'Remove plugin tables on deactivate', 'search-analytics' ) ?></span>
</label>
<br/>
<?php
@@ -345,7 +325,7 @@
<label>
<input type="hidden" name='mwtsa_settings[mwtsa_hide_charts]' value='0'/>
<input type='checkbox' name='mwtsa_settings[mwtsa_hide_charts]' value='1' <?php checked( $this->existing_options['mwtsa_hide_charts'], 1 ) ?> />
- <span><?php esc_attr_e( 'Hide graphical charts for representing statistics', 'search-analytics' ) ?></span>
+ <span><?php esc_html_e( 'Hide graphical charts for representing statistics', 'search-analytics' ) ?></span>
</label>
<br/>
<?php
@@ -359,10 +339,10 @@
<label>
<input type="hidden" name='mwtsa_settings[mwtsa_show_dates_as_utc]' value='0'/>
<input type='checkbox' name='mwtsa_settings[mwtsa_show_dates_as_utc]' value='1' <?php checked( $this->existing_options['mwtsa_show_dates_as_utc'], 1 ) ?> />
- <span><?php esc_attr_e( 'Show the results dates as UTC. Uncheck this to show the dates in the website timezone.', 'search-analytics' ) ?></span>
+ <span><?php esc_html_e( 'Show the results dates as UTC. Uncheck this to show the dates in the website timezone.', 'search-analytics' ) ?></span>
</label>
<br/>
- <strong><?php esc_attr_e( 'Unchecking this option might show results from adjacent days when filtering by date, depending on your website's timezone', 'search-analytics' ) ?></strong>
+ <strong><?php esc_html_e( 'Unchecking this option might show results from adjacent days when filtering by date, depending on your website's timezone', 'search-analytics' ) ?></strong>
<?php
}
@@ -374,10 +354,10 @@
<label>
<input type="hidden" name='mwtsa_settings[mwtsa_save_search_country]' value='0'/>
<input type='checkbox' name='mwtsa_settings[mwtsa_save_search_country]' value='1' <?php checked( $this->existing_options['mwtsa_save_search_country'], 1 ) ?> />
- <span><?php esc_attr_e( 'Save the country from where the search was launched', 'search-analytics' ) ?></span>
+ <span><?php esc_html_e( 'Save the country from where the search was launched', 'search-analytics' ) ?></span>
</label>
<br/>
- <strong><?php esc_attr_e( 'NOTE: this uses the <a href="https://ip-api.com">https://ip-api.com</a> JSON service which is limited to 150 requests per minute. In case you have more than 150 searches per minute on the website, please uncheck this checkbox. <br />In case the site's IP got banned, you can go here: <a href="https://ip-api.com/docs/unban">https://ip-api.com/docs/unban</a> and remove the ban.<br />A future version of Search Analytics will come with support for the PRO service of IP-API.com<br /><br />Disclaimer: I am not associated with the IP-API.com service in any way. I am just using it for providing you a way of finding out where the users search content from on your website.', 'search-analytics' ) ?></strong>
+ <strong><?php echo wp_kses_post( __( 'NOTE: this uses the <a href="https://ip-api.com">https://ip-api.com</a> JSON service which is limited to 150 requests per minute. In case you have more than 150 searches per minute on the website, please uncheck this checkbox. <br />In case the site's IP got banned, you can go here: <a href="https://ip-api.com/docs/unban">https://ip-api.com/docs/unban</a> and remove the ban.<br />A future version of Search Analytics will come with support for the PRO service of IP-API.com<br /><br />Disclaimer: I am not associated with the IP-API.com service in any way. I am just using it for providing you a way of finding out where the users search content from on your website.', 'search-analytics' ) ) ?></strong>
<?php
}
@@ -388,10 +368,10 @@
?>
<label>
<input type='checkbox' name='mwtsa_settings[mwtsa_save_search_by_user]' value='1' <?php checked( $this->existing_options['mwtsa_save_search_by_user'], 1 ) ?> />
- <span><?php esc_attr_e( 'Save the user id of the user who launched the search', 'search-analytics' ) ?></span>
+ <span><?php esc_html_e( 'Save the user id of the user who launched the search', 'search-analytics' ) ?></span>
</label>
<br/>
- <strong><?php esc_attr_e( 'Using this feature will allow you to see which of your registered users searched things on the site.', 'search-analytics' ) ?></strong>
+ <strong><?php esc_html_e( 'Using this feature will allow you to see which of your registered users searched things on the site.', 'search-analytics' ) ?></strong>
<?php
}
@@ -410,12 +390,12 @@
}
public function options_page() {
-
?>
- <form action='options.php' method='post'>
+ <form action="<?php echo esc_url( admin_url( 'options.php' ) ); ?>" method="post">
<?php
settings_fields( 'mwtsa_general_options' );
do_settings_sections( 'mwtsa_general_options' );
+
submit_button();
?>
</form>
@@ -424,30 +404,31 @@
$this->erase_history_form();
}
- function erase_history_form() {
+ protected function erase_history_form() {
?>
- <h3><?php esc_attr_e( 'Erase History', 'search-analytics' ) ?></h3>
+ <h3><?php esc_html_e( 'Erase History', 'search-analytics' ) ?></h3>
<table class="form-table erase-history-table">
<tbody>
<tr>
- <th scope="row"><?php esc_attr_e( 'Delete all data', 'search-analytics' ) ?></th>
+ <th scope="row"><?php esc_html_e( 'Delete all data', 'search-analytics' ) ?></th>
<td>
<form action="" method="post">
<?php wp_nonce_field( 'mwtsa-erase-data' ); ?>
<p class="submit">
<input name="mwtsa_erase_data" class="button-secondary" value="<?php esc_attr_e( 'Erase All Data', 'search-analytics' ) ?>" type="submit" onclick="return confirm( '<?php esc_attr_e( 'Are you sure you want to delete all data?nnClick `OK` to proceed.', 'search-analytics' ) ?>');"/><br/>
- <strong><?php esc_attr_e( 'Warning! Clicking this button will delete all historical search data', 'search-analytics' ) ?></strong>
+ <strong><?php esc_html_e( 'Warning! Clicking this button will delete all historical search data', 'search-analytics' ) ?></strong>
</p>
</form>
</td>
</tr>
<tr>
- <th scope="row"><?php esc_attr_e( 'Delete data older than', 'search-analytics' ) ?></th>
+ <th scope="row"><?php esc_html_e( 'Delete data older than', 'search-analytics' ) ?></th>
<td>
<form action="" method="post">
<?php wp_nonce_field( 'mwtsa-erase-data' ); ?>
<p class="submit">
+ <!--suppress HtmlFormInputWithoutLabel -->
<input type="number" name="mwtsa_data_older_than_days" value="90"/> <?php esc_attr_e( 'days', 'search-analytics' ) ?>
<input name="mwtsa_erase_old_data" class="button-secondary" value="<?php esc_attr_e( 'Erase Data', 'search-analytics' ) ?>" type="submit" onclick="return confirm( '<?php esc_attr_e( 'Are you sure you want to delete the selected data?nnClick `OK` to proceed.', 'search-analytics' ) ?>');"/>
</p>
@@ -459,12 +440,14 @@
<?php
}
- function erase_history( $older_than = 0 ) {
- global $wpdb, $mwtsa;
+ protected function erase_history( $older_than = 0 ) {
+ global $wpdb;
+
+ $instance = MWTSAI();
if ( $older_than == 0 ) {
- $wpdb->query( "TRUNCATE `$mwtsa->history_table_name`" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $mwtsa->history_table_name is hardcoded.
- $wpdb->query( "TRUNCATE `$mwtsa->terms_table_name`" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $mwtsa->terms_table_name is hardcoded.
+ $wpdb->query( "TRUNCATE `$instance->history_table_name`" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- $instance->history_table_name is hardcoded.
+ $wpdb->query( "TRUNCATE `$instance->terms_table_name`" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- $instance->terms_table_name is hardcoded.
} else {
try {
@@ -472,19 +455,22 @@
$_temp_date->sub( new DateInterval( 'P' . $older_than . 'D' ) );
$older_than_datetime = $_temp_date->format( 'Y-m-d H:i:s' );
- $wpdb->query( $wpdb->prepare( "DELETE FROM `$mwtsa->history_table_name` WHERE `datetime` < %s", $older_than_datetime ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $mwtsa->history_table_name is hardcoded.
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- $instance->history_table_name is hardcoded.
+ $wpdb->query( $wpdb->prepare( "DELETE FROM `$instance->history_table_name` WHERE `datetime` < %s", $older_than_datetime ) );
//TODO: delete recorded terms that no longer have at least 1 entry in the history table ?
} catch ( Exception $e ) {
}
}
+
+ wp_cache_set( 'last_changed', microtime(), 'mwtsa' );
}
- function data_erased_notice() {
+ protected function data_erased_notice() {
?>
<div class="notice updated mwtsa-notice is-dismissible">
- <p><?php esc_attr_e( 'Historical data successfully erased!', 'search-analytics' ); ?></p>
+ <p><?php esc_html_e( 'Historical data successfully erased!', 'search-analytics' ); ?></p>
</div>
<?php
}
@@ -492,4 +478,3 @@
}
-return new MWTSA_Admin_Settings();
No newline at end of file
--- a/search-analytics/admin/includes/class.stats-table.php
+++ b/search-analytics/admin/includes/class.stats-table.php
@@ -14,9 +14,12 @@
public function __construct( $args = array() ) {
parent::__construct( [
- 'title' => isset( $args['title'] ) ? esc_attr( $args['title'] ) : esc_attr__( 'Search Statistics', 'search-analytics' ),
- 'ajax' => isset( $args['ajax'] ) && $args['ajax']
+ 'title' => isset( $args['title'] ) ? esc_attr( $args['title'] ) : esc_attr__( 'Search Statistics', 'search-analytics' ),
+ 'ajax' => isset( $args['ajax'] ) && $args['ajax'],
+ 'plural' => 'mwtsa-table-search-terms',
+ 'singular' => 'mwtsa-table-search-term',
] );
+
}
public function display_search_box() {
@@ -24,7 +27,7 @@
}
public function get_this_screen() {
- return 'search-analytics/admin/includes/class.stats.php';
+ return 'mwtsa-search-analytics';
}
public function display_tablenav( $which ) {
@@ -32,6 +35,8 @@
?>
<div class="tablenav mwtsa_tablenav <?php echo esc_attr( $which ); ?>">
+ <?php wp_nonce_field( 'bulk-' . $this->_args['plural'] ); ?>
+
<?php if ( $this->has_items() && ! empty( $this->get_bulk_actions() ) ): ?>
<div class="alignleft actions bulkactions">
<?php $this->bulk_actions( $which ); ?>
@@ -104,16 +109,28 @@
}
/**
- * @deprecated deprecated since version 1.3.6. WIll be removed in version 2.0.0
+ * Note: It uses the `'column_' . $column_name` within single_row_columns()
*/
public function column_term( $item ) {
$page = isset( $_REQUEST['page'] ) ? sanitize_text_field( $_REQUEST['page'] ) : ''; //phpcs:ignore WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- we actually need slashes here - for now
+
+ $delete_url = wp_nonce_url(
+ add_query_arg(
+ array( 'page' => $page, 'action' => 'delete', 'search-term' => (int) $item['id'] ),
+ admin_url( 'admin.php' )
+ ),
+ 'mwtsa_delete_term_' . (int) $item['id']
+ );
+
+ $view_url = $this->get_view_url($page, $item['id']);
+
$actions = array(
- 'delete' => sprintf( '<a href="?page=%s&action=%s&search-term=%d">' . esc_attr__( 'Delete', 'search-analytics' ) . '</a>', esc_attr( $page ), 'delete', (int) $item['id'] ),
- 'view' => sprintf( '<a href="?page=%s&search-term=%d">' . esc_attr__( 'View Details', 'search-analytics' ) . '</a>', esc_attr( $page ), (int) $item['id'] )
+ 'delete' => '<a href="' . esc_url( $delete_url ) . '">' . esc_attr__( 'Delete', 'search-analytics' ) . '</a>',
+ 'view' => '<a href="' . esc_url( $view_url ) . '">' . esc_attr__( 'View Details', 'search-analytics' ) . '</a>'
);
- return sprintf( '<a href="?page=%1$s&search-term=%2$d">%3$s</a> %4$s', esc_attr( $page ), (int) $item['id'], esc_attr( $item['term'] ), $this->row_actions( $actions ) );
+ /** @noinspection HtmlUnknownTarget */
+ return sprintf( '<a href="%1$s">%2$s</a> %3$s', esc_url( $view_url ), esc_attr( $item['term'] ), $this->row_actions( $actions ) );
}
public function column_cb( $item ) {
@@ -128,50 +145,68 @@
);
}
- // phpcs:disable WordPress.Security.NonceVerification.Recommended
+ protected function get_view_url($page, $item_id) {
+ return add_query_arg(
+ array( 'page' => $page, 'search-term' => $item_id ),
+ admin_url( 'admin.php' )
+ );
+ }
+
function process_bulk_action() {
- global $wpdb, $mwtsa;
+ global $wpdb;
- if ( 'delete' === $this->current_action() && ! empty( $_GET['search-term'] ) ) {
+ if ( 'delete' !== $this->current_action() || empty( $_GET['search-term'] ) ) {
+ return;
+ }
+
+ if ( ! current_user_can( 'manage_options' ) ) {
+ wp_die( esc_html__( 'You are not allowed to delete search terms.', 'search-analytics' ), 403 );
+ }
+
+ if ( is_array( $_GET['search-term'] ) ) {
+ check_admin_referer( 'bulk-' . $this->_args['plural'] );
+ } else {
+ check_admin_referer( 'mwtsa_delete_term_' . (int) $_GET['search-term'] );
+ }
+
+ $terms_to_delete = array_map( 'absint', (array) $_GET['search-term'] );
+ $terms_placeholders = implode( ',', array_fill( 0, count( $terms_to_delete ), '%d' ) );
+
+ $instance = MWTSAI();
+
+ // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare,PluginCheck.Security.DirectDB.UnescapedDBParameter -- table names are hardcoded.
+ $wpdb->query(
+ $wpdb->prepare(
+ "DELETE FROM $instance->terms_table_name WHERE id IN ($terms_placeholders)",
+ $terms_to_delete
+ )
+ );
+
+ $wpdb->query(
+ $wpdb->prepare(
+ "DELETE FROM $instance->history_table_name WHERE term_id IN ($terms_placeholders)",
+ $terms_to_delete
+ )
+ );
+ // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare,PluginCheck.Security.DirectDB.UnescapedDBParameter
- $terms_to_delete = array_map( 'absint', (array) $_GET['search-term'] );
- $terms_placeholders = implode( ',', array_fill( 0, count( $terms_to_delete ), '%d' ) );
+ wp_cache_set( 'last_changed', microtime(), 'mwtsa' );
- $wpdb->query( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
- $wpdb->prepare(
- "DELETE FROM $mwtsa->terms_table_name WHERE id IN ($terms_placeholders)", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
- $terms_to_delete
- )
- );
- $wpdb->query( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
- $wpdb->prepare(
- "DELETE FROM $mwtsa->history_table_name WHERE term_id IN ($terms_placeholders)", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
- $terms_to_delete
- )
- );
-
- wp_die(
- sprintf( '%s <a href="%s">%s</a>',
- esc_attr__( 'Items deleted!', 'search-analytics' ),
- esc_url( add_query_arg( 'result', 'deleted', remove_query_arg( array(
- 'action',
- 'search-term'
- ) ) ) ),
- esc_attr__( 'Go Back!', 'search-analytics' )
- )
- );
- }
+ wp_safe_redirect( add_query_arg( 'result', 'deleted', remove_query_arg( array( 'action', 'search-term' ) ) ) );
+ exit;
}
- // phpcs:enable WordPress.Security.NonceVerification.Recommended
public function column_default( $item, $column_name ) {
- $output = esc_attr__( 'N/A Yet', 'search-analytics' );
+ $output = esc_html__( 'N/A Yet', 'search-analytics' );
switch ( $column_name ) {
case 'term':
$page = isset( $_REQUEST['page'] ) ? sanitize_text_field( $_REQUEST['page'] ) : ''; //phpcs:ignore WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- we actually need slashes here - for now
- $output = sprintf( '<a href="?page=%s&search-term=%s">%s</a>', esc_attr( $page ), (int) $item['id'], esc_attr( $item['term'] ) );
+ $view_url = $this->get_view_url($page, $item['id']);
+
+ /** @noinspection HtmlUnknownTarget */
+ $output = sprintf( '<a href="%1$s">%2$s</a>', esc_url( $view_url ), esc_attr( $item['term'] ) );
break;
case 'searches':
$output = (int) $item['count'];
@@ -180,14 +215,14 @@
$output = number_format( (float) $item['results_count'], 2, '.', '' );
break;
case 'last_search_date_utc':
- $output = date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), strtotime( $item['last_search_date'] ) );
+ $output = esc_html( date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), strtotime( $item['last_search_date'] ) ) );
break;
case 'last_search_date':
- $output = date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), strtotime( $item['last_search_date'] ) + wp_timezone()->getOffset( new DateTime( $item['last_search_date'] ) ) );
+ $output = esc_html( date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), strtotime( $item['last_search_date'] ) + mwtsa_wp_timezone()->getOffset( new DateTime( $item['last_search_date'] ) ) ) );
break;
case 'country':
if ( empty( $item['country'] ) ) {
- $output = esc_attr__( 'N/A', 'search-analytics' );
+ $output = esc_html__( 'N/A', 'search-analytics' );
break;
}
@@ -201,12 +236,12 @@
$country_name = strtoupper( $item_country );
}
- $output = '<div><img src="' . MWTSAI()->plugin_admin_url . 'assets/images/flags/' . $item_country . '.png" alt="' . $country_name . '" /> <span>' . ucwords( $country_name ) . '</span></div>';
+ $output = '<div><img src="' . esc_url( MWTSAI()->plugin_admin_url . 'assets/images/flags/' . $item_country . '.png' ) . '" alt="' . esc_attr( $country_name ) . '" /> <span>' . esc_html( ucwords( $country_name ) ) . '</span></div>';
break;
case 'user':
if ( empty( $item['user_id'] ) ) {
- $output = esc_attr__( 'N/A', 'search-analytics' );
+ $output = esc_html__( 'N/A', 'search-analytics' );
break;
}
@@ -214,11 +249,11 @@
$user_data = get_userdata( (int) $item['user_id'] );
if ( ! $user_data ) {
- $output = esc_attr__( 'N/A', 'search-analytics' );
+ $output = esc_html__( 'N/A', 'search-analytics' );
break;
}
- $output = '<a href="' . get_edit_user_link( $user_data->ID ) . '">' . esc_attr( $user_data->user_nicename ) . '</a>';
+ $output = '<a href="' . esc_url( get_edit_user_link( $user_data->ID ) ) . '">' . esc_attr( $user_data->user_nicename ) . '</a>';
break;
}
@@ -325,8 +360,10 @@
ob_start();
?>
<div class="date-interval">
+ <!--suppress HtmlFormInputWithoutLabel -->
<input type="text" name="date_from" class="date-picker field-from" placeholder="<?php esc_attr_e( 'Start Date', 'search-analytics' ) ?>" value="<?php echo esc_attr( $date_from ) ?>">
<span class="dashicons dashicons-minus"></span>
+ <!--suppress HtmlFormInputWithoutLabel -->
<input type="text" name="date_to" class="date-picker field-to" placeholder="<?php esc_attr_e( 'End Date', 'search-analytics' ) ?>" value="<?php echo esc_attr( $date_to ) ?>">
</div>
<?php
@@ -335,12 +372,15 @@
}
function filter_user() {
- global $wpdb, $mwtsa;
+ global $wpdb;
wp_enqueue_style( 'select2css' );
$selected_user = isset( $_REQUEST['filter-user'] ) ? (int) $_REQUEST['filter-user'] : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+ $instance = MWTSAI();
- $users_with_searches = $wpdb->get_results( "SELECT `ID`, `user_nicename` FROM $wpdb->users WHERE `ID` IN ( SELECT DISTINCT(`user_id`) FROM {$mwtsa->history_table_name})" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
+ // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.InterpolatedNotPrepared,PluginCheck.Security.DirectDB.UnescapedDBParameter -- $instance->history_table_name and $wpdb->users are hardcoded.
+ $users_with_searches = $wpdb->get_results( "SELECT `ID`, `user_nicename` FROM $wpdb->users WHERE `ID` IN ( SELECT DISTINCT(`user_id`) FROM {$instance->history_table_name})" );
+ // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.InterpolatedNotPrepared,PluginCheck.Security.DirectDB.UnescapedDBParameter
if ( empty( $users_with_searches ) ) {
return '';
@@ -349,16 +389,21 @@
ob_start();
?>
<select class="select2-select" name="filter-user">
- <option value=""><?php esc_attr_e( 'Filter by user ...', 'search-analytics' ) ?></option>
+ <option value=""><?php esc_html_e( 'Filter by user ...', 'search-analytics' ) ?></option>
<?php foreach ( $users_with_searches as $user ) :
- printf( "<option value='%d' %s>%s</option>", (int) $user->ID, selected( (int) $user->ID, $selected_user, false ), esc_attr( $user->user_nicename ) );
+ /** @noinspection HtmlUnknownAttribute */
+ printf( "<option value='%d' %s>%s</option>", (int) $user->ID, selected( (int) $user->ID, $selected_user, false ), esc_attr( $user->user_nicename ) );
endforeach; ?>
</select>
<?php
return ob_get_clean();
}
- public function display_time_views() {
+ /**
+ * @noinspection HtmlUnknownTarget
+ * @noinspection HtmlUnknownAttribute
+ */
+ public function display_time_views() {
$views = [];
$current = isset( $_REQUEST['period_view'] ) ? (int) $_REQUEST['period_view'] : 3; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
@@ -381,6 +426,10 @@
$this->format_views_list( $views );
}
+ /**
+ * @noinspection HtmlUnknownTarget
+ * @noinspection HtmlUnknownAttribute
+ */
public function display_results_views() {
$views = array();
$current = ! empty( $_REQUEST['results_view'] ) ? (int) $_REQUEST['results_view'] : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
@@ -400,6 +449,10 @@
$this->format_views_list( $views );
}
+ /**
+ * @noinspection HtmlUnknownTarget
+ * @noinspection HtmlUnknownAttribute
+ */
public function display_results_grouping() {
$views = array();
$current = ! empty( $_REQUEST['grouped_view'] ) ? (int) $_REQUEST['grouped_view'] : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
@@ -435,10 +488,46 @@
if ( isset( $_GET['result'] ) && $_GET['result'] === 'deleted' ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
?>
<div class="notice updated mwtsa-notice is-dismissible">
- <p><?php esc_attr_e( 'Search term(s) successfully deleted', 'search-analytics' ); ?></p>
+ <p><?php esc_html_e( 'Search term(s) successfully deleted', 'search-analytics' ); ?></p>
</div>
<?php
}
}
+
+ public function mwtsa_init() {
+
+ if ( ! isset( $_REQUEST['mwtsa-export-csv'] ) ) {
+ return;
+ }
+
+ if ( ! current_user_can( 'manage_options' ) ) {
+ wp_die( esc_html__( 'You are not allowed to export data.', 'search-analytics' ), 403 );
+ }
+
+ check_admin_referer( 'bulk-' . $this->_args['plural'] );
+
+ $columns = array(
+ esc_attr__( 'Term ID', 'search-analytics' ),
+ esc_attr__( 'Term', 'search-analytics' ),
+ esc_attr__( 'Searches', 'search-analytics' ),
+ esc_attr__( 'Average Results', 'search-analytics' ),
+ esc_attr__( 'Last Search Date', 'search-analytics' )
+ );
+
+ if ( ! empty( $_REQUEST['search-term'] ) ) {
+ $columns = array(
+ esc_attr__( 'Average Results', 'search-analytics' ),
+ esc_attr__( 'Date and Time', 'search-analytics' )
+ );
+
+ if ( ! empty( $_REQUEST['grouped_view'] ) ) {
+ $columns[] = esc_attr__( 'Searches', 'search-analytics' );
+ }
+ }
+
+ $export_csv = new MWTSA_Export_CSV();
+ $export_csv->mwtsa_export_to_csv( ( new MWTSA_History_Data )->get_terms_history_data(), '', $columns );
+
+ }
}
endif;
No newline at end of file
--- a/search-analytics/admin/includes/class.stats.php
+++ b/search-analytics/admin/includes/class.stats.php
@@ -11,19 +11,23 @@
private $view;
private $charts;
+ /**
+ * @var bool
+ */
+ private $is_delete;
+ /**
+ * @var MWTSA_Stats_Table|MWTSA_Term_Stats_Table
+ */
+ private $stats_table;
- public function __construct() {
+ public function __construct() {
- $this->view = 'dashboard_page_search-analytics/admin/includes/class.stats';
+ $this->view = '';
$this->set_constants();
$this->plugin_options = MWTSA_Options::get_options();
- add_action( 'init', array( $this, 'mwtsa_init' ) );
-
- add_action( 'admin_menu', array( $this, 'add_admin_menu' ) );
add_action( 'admin_enqueue_scripts', array( $this, 'load_admin_assets' ) );
- add_action( "load-$this->view", array( $this, 'add_screen_options' ) );
add_filter( 'set-screen-option', array( $this, 'set_screen_options' ), 10, 3 );
if ( empty( $_REQUEST['search-term'] ) && empty ( MWTSA_Options::get_option( 'mwtsa_hide_charts' ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
@@ -34,31 +38,10 @@
include_once( 'class.term-stats.php' );
}
- public function mwtsa_init() {
-
- if ( isset( $_REQUEST['mwtsa-export-csv'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
- $columns = array(
- esc_attr__( 'Term ID', 'search-analytics' ),
- esc_attr__( 'Term', 'search-analytics' ),
- esc_attr__( 'Searches', 'search-analytics' ),
- esc_attr__( 'Average Results', 'search-analytics' ),
- esc_attr__( 'Last Search Date', 'search-analytics' )
- );
-
- if ( ! empty( $_REQUEST['search-term'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
- $columns = array(
- esc_attr__( 'Average Results', 'search-analytics' ),
- esc_attr__( 'Date and Time', 'search-analytics' )
- );
-
- if ( ! empty( $_REQUEST['grouped_view'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
- $columns[] = esc_attr__( 'Searches', 'search-analytics' );
- }
- }
-
- $export_csv = new MWTSA_Export_CSV();
- $export_csv->mwtsa_export_to_csv( ( new MWTSA_History_Data )->get_terms_history_data(), '', $columns );
- }
+ public function init_stats_table() {
+ $this->is_delete = ! empty( $_REQUEST['action'] ) && 'delete' === $_REQUEST['action']; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+ $this->stats_table = ! empty( $_REQUEST['search-term'] ) && ! $this->is_delete ? new MWTSA_Term_Stats_Table( array( 'search-term' => (int) $_REQUEST['search-term'] ) ) : new MWTSA_Stats_Table(); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+ $this->stats_table->mwtsa_init();
}
public function add_screen_options() {
@@ -89,89 +72,71 @@
);
}
- public function add_admin_menu() {
- $this_user_role = mwt_get_current_user_roles();
- $accepted_user_roles = array_values( array_intersect( $this_user_role, $this->plugin_options['mwtsa_display_stats_for_role'] ) );
-
- if ( ! isset( $this->plugin_options['mwtsa_display_stats_for_role'] ) || ! empty( $accepted_user_roles ) ) {
-
- //TODO: change __FILE__ to unique slug - https://docs.wpvip.com/php_codesniffer/warnings/#h-using-file-for-page-registration
- add_submenu_page( 'index.php', __( 'Search Analytics', 'search-analytics' ), __( 'Search Analytics', 'search-analytics' ), $accepted_user_roles[0], __FILE__, array(
- &$this,
- 'render_stats_page'
- ) );
-
- }
+ public function set_view( $view ) {
+ $this->view = $view;
}
public function load_admin_assets( $hook ) {
- global $mwtsa;
-
- wp_enqueue_style( 'mwtsa-stats-style', $mwtsa->plugin_admin_url . 'assets/css/stats-style.css', array(), $mwtsa->version );
+ wp_enqueue_style( 'mwtsa-stats-style', MWTSAI()->plugin_admin_url . 'assets/css/stats-style.css', array(), MWTSAI()->version );
if ( $hook != $this->view ) {
return;
}
if ( ! empty( MWTSA_Options::get_option( 'mwtsa_save_search_by_user' ) ) ) {
- wp_register_style( 'select2css', '//cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/css/select2.min.css', false, '4.0.13' );
+ wp_register_style( 'select2css', MWTSAI()->plugin_admin_url . 'assets/css/select2.min.css', false, '4.0.13' );
- wp_enqueue_script( 'select2', '//cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/js/select2.min.js', array( 'jquery' ), '4.0.13', true );
+ wp_enqueue_script( 'select2', MWTSAI()->plugin_admin_url . 'assets/js/select2.min.js', array( 'jquery' ), '4.0.13', true );
}
- wp_register_style( 'mwtsa-datepicker-ui', '//code.jquery.com/ui/1.11.2/themes/smoothness/jquery-ui.css', array(), '1.11.2' );
+ wp_register_style( 'mwtsa-datepicker-ui', MWTSAI()->plugin_admin_url . 'assets/css/jquery-ui-smoothness.css', array(), '1.14.2' );
- wp_enqueue_script( 'mwtsa-admin-script', $mwtsa->plugin_admin_url . 'assets/js/admin.js', array(), $mwtsa->version, true );
+ wp_enqueue_script( 'mwtsa-admin-script', MWTSAI()->plugin_admin_url . 'assets/js/admin.js', array(), MWTSAI()->version, true );
wp_localize_script( 'mwtsa-admin-script', 'mwtsa_admin_obj', array(
- 'gmt_offset' => wp_timezone()->getOffset( new DateTime() ),
- 'date_format' => mwt_wp_date_format_to_js_datepicker_format( get_option( 'date_format' ) )
+ 'gmt_offset' => mwtsa_wp_timezone()->getOffset( new DateTime() ),
+ 'date_format' => mwtsa_wp_date_format_to_js_datepicker_format( get_option( 'date_format' ) )
)
);
}
// phpcs:disable WordPress.Security.NonceVerification.Recommended
public function render_stats_page() {
- global $mwtsa;
-
- $is_delete = ! empty( $_REQUEST['action'] ) && 'delete' === $_REQUEST['action'];
- $stats_table = ! empty( $_REQUEST['search-term'] ) && ! $is_delete ? new MWTSA_Term_Stats_Table( array( 'search-term' => (int) $_REQUEST['search-term'] ) ) : new MWTSA_Stats_Table();
-
?>
<div class="wrap mwtsa-wrapper">
<div class="mwtsa-2-col">
<div class="mwtsa-col-1">
<div class="col-content">
- <?php $stats_table->load_notices(); ?>
- <?php echo $stats_table->this_title(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- already escaped ?>
- <?php if ( ! $is_delete ) : ?>
+ <?php $this->stats_table->load_notices(); ?>
+ <?php echo $this->stats_table->this_title(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- already escaped ?>
+ <?php if ( ! $this->is_delete ) : ?>
<div class="mwtsa-filters-groups-wrapper">
<div>
<span class="views-label"><?php esc_html_e( 'Time filters:', 'search-analytics' ) ?></span>
- <?php $stats_table->display_time_views(); ?>
+ <?php $this->stats_table->display_time_views(); ?>
</div>
<div>
<span class="views-label"><?php esc_html_e( 'Results filters:', 'search-analytics' ) ?></span>
- <?php $stats_table->display_results_views(); ?>
+ <?php $this->stats_table->display_results_views(); ?>
</div>
<?php if ( ! empty( $_REQUEST['search-term'] ) ) :?>
<div>
<span class="views-label"><?php esc_html_e( 'Group By:', 'search-analytics' ) ?></span>
- <?php $stats_table->display_group_views(); ?>
+ <?php $this->stats_table->display_group_views(); ?>
</div>
<?php else : ?>
<div>
<span class=