Skip to content
Merged
17 changes: 14 additions & 3 deletions src/Admin/Module.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,12 @@ private function init() {
*
*/
public function maybe_install_module( $old_settings, $settings ) {
if ( $settings['proxy_enabled'] === 'on' && $old_settings['proxy_enabled'] !== 'on' ) {
$settings_proxy = ( is_array( $settings ) && isset( $settings['proxy_enabled'] ) ) ? $settings['proxy_enabled'] : '';
$old_proxy = ( is_array( $old_settings ) && isset( $old_settings['proxy_enabled'] ) ) ? $old_settings['proxy_enabled'] : '';

if ( $settings_proxy === 'on' && $old_proxy !== 'on' ) {
$this->install();
} elseif ( $settings['proxy_enabled'] === '' && $old_settings['proxy_enabled'] === 'on' ) {
} elseif ( $settings_proxy === '' && $old_proxy === 'on' ) {
$this->uninstall();
}
}
Expand Down Expand Up @@ -196,7 +199,10 @@ public function maybe_enable_proxy( $settings, $old_settings ) {
/**
* No need to run this on each update run, or when the proxy is disabled.
*/
if ( empty( $settings['proxy_enabled'] ) || ( $settings['proxy_enabled'] === 'on' && $old_settings['proxy_enabled'] === 'on' ) ) {
$new_proxy_setting = ( is_array( $settings ) && isset( $settings['proxy_enabled'] ) ) ? $settings['proxy_enabled'] : '';
$old_proxy_setting = ( is_array( $old_settings ) && isset( $old_settings['proxy_enabled'] ) ) ? $old_settings['proxy_enabled'] : '';

if ( empty( $new_proxy_setting ) || ( $new_proxy_setting === 'on' && $old_proxy_setting === 'on' ) ) {
return $settings;
}

Expand Down Expand Up @@ -259,6 +265,11 @@ private function is_ssl() {
* @since 1.3.0
*/
private function test_proxy( $run = true ) {
// Always succeed if this is a CI environment.
if ( defined( 'PLAUSIBLE_CI' ) ) {
return true;
}

// Should we run the test?
if ( ! apply_filters( 'plausible_analytics_module_run_test_proxy', $run ) ) {
return false; // @codeCoverageIgnore
Expand Down
113 changes: 69 additions & 44 deletions src/Ajax.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,15 +76,15 @@ public function fetch_messages() {
public function quit_wizard() {
$request_data = $this->clean( $_REQUEST );

if ( ! current_user_can( 'manage_options' ) || wp_verify_nonce( $request_data[ '_nonce' ], 'plausible_analytics_quit_wizard' ) < 1 ) {
if ( ! current_user_can( 'manage_options' ) || wp_verify_nonce( $request_data['_nonce'], 'plausible_analytics_quit_wizard' ) < 1 ) {
Messages::set_error( __( 'Not allowed', 'plausible-analytics' ) );

wp_send_json_error( null, 403 );
}

update_option( 'plausible_analytics_wizard_done', true );

$this->maybe_handle_redirect( $request_data[ 'redirect' ] );
$this->maybe_handle_redirect( $request_data['redirect'] );

wp_send_json_success();
}
Expand All @@ -93,26 +93,41 @@ public function quit_wizard() {
* Clean variables using `sanitize_text_field`.
* Arrays are cleaned recursively. Non-scalar values are ignored.
*
* @since 1.3.0
* @access public
*
* @param string|array $var Sanitize the variable.
*
* @return string|array
* @since 1.3.0
* @access public
*
*/
private function clean( $var ) {
private function clean( $var, $key = '' ) {
// If the variable is an array, recursively apply the function to each element of the array.
if ( is_array( $var ) ) {
return array_map( [ $this, 'clean' ], $var );
$cleaned = [];

foreach ( $var as $k => $v ) {
$cleaned[ $k ] = $this->clean( $v, $k );
}

return $cleaned;
}

// If the variable is a scalar value (string, integer, float, boolean).
if ( is_scalar( $var ) ) {
/**
* If the variable is the options object, we only unslash it, but don't sanitize it yet.
* Sanitization will happen after json_decode.
*/
if ( $key === 'options' ) {
return wp_unslash( $var );
}

// Parse the variable using the wp_parse_url function.
$parsed = wp_parse_url( $var );

// If the variable has a scheme (e.g. http:// or https://), sanitize the variable using the esc_url_raw function.
if ( isset( $parsed[ 'scheme' ] ) ) {
return esc_url_raw( wp_unslash( $var ), [ $parsed[ 'scheme' ] ] );
if ( isset( $parsed['scheme'] ) ) {
return esc_url_raw( wp_unslash( $var ) );
}

// If the variable does not have a scheme, sanitize the variable using the sanitize_text_field function.
Expand Down Expand Up @@ -157,54 +172,54 @@ private function maybe_handle_redirect( $direction ) {
public function show_wizard() {
$request_data = $this->clean( $_REQUEST );

if ( ! current_user_can( 'manage_options' ) || wp_verify_nonce( $request_data[ '_nonce' ], 'plausible_analytics_show_wizard' ) < 1 ) {
if ( ! current_user_can( 'manage_options' ) || wp_verify_nonce( $request_data['_nonce'], 'plausible_analytics_show_wizard' ) < 1 ) {
Messages::set_error( __( 'Not allowed.', 'plausible-analytics' ) );

wp_send_json_error( null, 403 );
}

delete_option( 'plausible_analytics_wizard_done' );

$this->maybe_handle_redirect( $request_data[ 'redirect' ] );
$this->maybe_handle_redirect( $request_data['redirect'] );

wp_send_json_success();
}

/**
* Save Admin Settings
*
* @since 1.0.0
* @return void
* @since 1.0.0
*/
public function toggle_option() {
// Sanitize all the post data before using.
$post_data = $this->clean( $_POST );
$settings = Helpers::get_settings();

if ( ! current_user_can( 'manage_options' ) || wp_verify_nonce( $post_data[ '_nonce' ], 'plausible_analytics_toggle_option' ) < 1 ) {
if ( ! current_user_can( 'manage_options' ) || wp_verify_nonce( $post_data['_nonce'], 'plausible_analytics_toggle_option' ) < 1 ) {
wp_send_json_error( __( 'Not allowed.', 'plausible-analytics' ), 403 );
}

if ( $post_data[ 'is_list' ] ) {
if ( $post_data['is_list'] ) {
/**
* Toggle lists.
*/
if ( $post_data[ 'toggle_status' ] === 'on' ) {
if ( $post_data['toggle_status'] === 'on' ) {
// If toggle is on, store the value under a new key.
if ( ! in_array( $post_data[ 'option_value' ], $settings[ $post_data[ 'option_name' ] ] ) ) {
$settings[ $post_data[ 'option_name' ] ][] = $post_data[ 'option_value' ];
if ( ! in_array( $post_data['option_value'], $settings[ $post_data['option_name'] ] ) ) {
$settings[ $post_data['option_name'] ][] = $post_data['option_value'];
}
} else {
// If toggle is off, find the key by its value and unset it.
if ( ( $key = array_search( $post_data[ 'option_value' ], $settings[ $post_data[ 'option_name' ] ] ) ) !== false ) {
unset( $settings[ $post_data[ 'option_name' ] ][ $key ] );
if ( ( $key = array_search( $post_data['option_value'], $settings[ $post_data['option_name'] ] ) ) !== false ) {
unset( $settings[ $post_data['option_name'] ][ $key ] );
}
}
} else {
/**
* Single toggles.
*/
$settings[ $post_data[ 'option_name' ] ] = $post_data[ 'toggle_status' ];
$settings[ $post_data['option_name'] ] = $post_data['toggle_status'];
}

// Update all the options to plausible settings.
Expand All @@ -213,22 +228,22 @@ public function toggle_option() {
/**
* Allow devs to perform additional actions.
*/
do_action( 'plausible_analytics_settings_saved', $settings, $post_data[ 'option_name' ], $post_data[ 'toggle_status' ] );
do_action( 'plausible_analytics_settings_saved', $settings, $post_data['option_name'], $post_data['toggle_status'] );

$option_label = $post_data[ 'option_label' ];
$toggle_status = $post_data[ 'toggle_status' ] === 'on' ? __( 'enabled', 'plausible-analytics' ) : __( 'disabled', 'plausible-analytics' );
$option_label = $post_data['option_label'];
$toggle_status = $post_data['toggle_status'] === 'on' ? __( 'enabled', 'plausible-analytics' ) : __( 'disabled', 'plausible-analytics' );
$message = apply_filters(
'plausible_analytics_toggle_option_success_message',
sprintf( '%s %s.', $option_label, $toggle_status ),
$post_data[ 'option_name' ],
$post_data[ 'toggle_status' ]
$post_data['option_name'],
$post_data['toggle_status']
);

Messages::set_success( $message );

$additional = $this->maybe_render_additional_message( $post_data[ 'option_name' ], $post_data[ 'toggle_status' ] );
$additional = $this->maybe_render_additional_message( $post_data['option_name'], $post_data['toggle_status'] );

Messages::set_additional( $additional, $post_data[ 'option_name' ] );
Messages::set_additional( $additional, $post_data['option_name'] );

wp_send_json_success( null, 200 );
}
Expand Down Expand Up @@ -271,17 +286,21 @@ public function save_options() {
$post_data = $this->clean( $_POST );
$settings = Helpers::get_settings();

if ( ! current_user_can( 'manage_options' ) || wp_verify_nonce( $post_data[ '_nonce' ], 'plausible_analytics_toggle_option' ) < 1 ) {
if ( ! current_user_can( 'manage_options' ) || wp_verify_nonce( $post_data['_nonce'], 'plausible_analytics_toggle_option' ) < 1 ) {
Messages::set_error( __( 'Not allowed.', 'plausible-analytics' ) );

wp_send_json_error( null, 403 );
}

$options = json_decode( $post_data[ 'options' ] );
$options = json_decode( $post_data['options'] );

if ( empty( $options ) ) {
Messages::set_error( __( 'No options found to save.', 'plausible-analytics' ) );

if ( defined( 'PLAUSIBLE_CI' ) ) {
return;
}

wp_send_json_error( null, 400 );
}

Expand All @@ -298,46 +317,52 @@ function ( $option ) {
);

if ( count( $input_array_elements ) > 0 ) {
$options = [];
$array_name = preg_replace( '/\[[0-9]+]/', '', $input_array_elements[ 0 ]->name );
$options[ 0 ] = (object) [];
$options[ 0 ]->name = $array_name;
$options = [];
$array_name = preg_replace( '/\[[0-9]+]/', '', $input_array_elements[0]->name );
$options[0] = (object) [];
$options[0]->name = $array_name;
$options[0]->value = [];

foreach ( $input_array_elements as $input_array_element ) {
if ( $input_array_element->value ) {
$options[ 0 ]->value[] = $input_array_element->value;
$options[0]->value[] = $input_array_element->value;
}
}
}

foreach ( $options as $option ) {
$name = sanitize_text_field( $option->name );
$value = $this->clean( $option->value );

// Clean spaces
if ( is_string( $option->value ) ) {
$settings[ $option->name ] = trim( $option->value );
if ( is_string( $value ) ) {
$settings[ $name ] = trim( $value );
} else {
$settings[ $option->name ] = $option->value;
$settings[ $name ] = $value;
}

// Validate Plugin Token if this is the Plugin Token field.
if ( $option->name === 'api_token' ) {
$this->validate_api_token( $option->value );
if ( $name === 'api_token' ) {
$this->validate_api_token( $value );

$additional = $this->maybe_render_additional_message( $option->name, $option->value );
$additional = $this->maybe_render_additional_message( $name, $value );

Messages::set_additional( $additional, $option->name );
Messages::set_additional( $additional, $name );
}

// Refresh Tracker ID if Domain Name has changed (e.g. after migration from staging to production)
if ($option->name === 'domain_name') {
delete_option('plausible_analytics_tracker_id');
if ( $name === 'domain_name' ) {
delete_option( 'plausible_analytics_tracker_id' );
}
}

update_option( 'plausible_analytics_settings', $settings );

Messages::set_success( __( 'Settings saved.', 'plausible-analytics' ) );

wp_send_json_success( null, 200 );
if ( ! defined( 'PLAUSIBLE_CI' ) ) {
wp_send_json_success( null, 200 );
}
}

/**
Expand Down
11 changes: 6 additions & 5 deletions src/Assets.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public function __construct() {
* @return void
*/
private function init() {
add_action( 'wp_enqueue_scripts', [ $this, 'maybe_enqueue_main_script' ] );
add_action( 'wp_enqueue_scripts', [ $this, 'maybe_enqueue_main_script' ], 1 );
add_action( 'wp_enqueue_scripts', [ $this, 'maybe_enqueue_cloaked_affiliate_links_assets' ], 11 );
add_action( 'wp_enqueue_scripts', [ $this, 'maybe_enqueue_four_o_four_script' ], 11 );
add_action( 'wp_enqueue_scripts', [ $this, 'maybe_enqueue_query_params_script' ], 11 );
Expand All @@ -41,17 +41,18 @@ public function maybe_enqueue_main_script() {
$settings = Helpers::get_settings();
$user_role = Helpers::get_user_role();

/**
* This is a dummy script that will allow us to attach inline scripts further down the line.
*/
wp_register_script( 'plausible-analytics', '' );

/**
* Bail if tracked_user_roles is empty (which means no roles should be tracked) or if the current role should not be tracked.
*/
if ( ( ! empty( $user_role ) && ! isset( $settings['tracked_user_roles'] ) ) || ( ! empty( $user_role ) && ! in_array( $user_role, $settings['tracked_user_roles'], true ) ) ) {
return; // @codeCoverageIgnore
}

/**
* This is a dummy script that will allow us to attach inline scripts further down the line.
*/
wp_register_script( 'plausible-analytics', '' );
wp_enqueue_script(
'plausible-analytics',
'',
Expand Down
11 changes: 0 additions & 11 deletions src/Helpers.php
Original file line number Diff line number Diff line change
Expand Up @@ -116,17 +116,6 @@ public static function get_settings() {

$settings = get_option( 'plausible_analytics_settings', [] );

/**
* If this is an AJAX request, make sure the latest settings are used.
*/
if ( isset( $_POST['action'] ) && $_POST['action'] === 'plausible_analytics_save_options' ) {
$options = json_decode( str_replace( '\\', '', $_POST['options'] ) );

foreach ( $options as $option ) {
$settings[ $option->name ] = $option->value;
}
}

return apply_filters( 'plausible_analytics_settings', wp_parse_args( $settings, $defaults ) );
}

Expand Down
10 changes: 10 additions & 0 deletions tests/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ public function __construct() {
define( 'PLAUSIBLE_TESTS_ROOT', __DIR__ . '/' );
}

if ( ! defined( 'PLAUSIBLE_CI' ) ) {
define( 'PLAUSIBLE_CI', true );
}

parent::__construct();
}

Expand Down Expand Up @@ -241,6 +245,12 @@ public function setQueryParams( $settings ) {
return $settings;
}

public function enableAdministratorTracking( $settings ) {
$settings['tracked_user_roles'][] = 'administrator';

return $settings;
}

/**
* Checks an array for a (partial) match with $string.
*
Expand Down
3 changes: 2 additions & 1 deletion tests/TestableHelpers.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

namespace Plausible\Analytics\Tests;

use Plausible\Analytics\WP\Client;
use Plausible\Analytics\WP\Helpers;

/**
Expand All @@ -15,7 +16,7 @@ class TestableHelpers extends Helpers {
* @return
*/
protected static function get_client() {
return new class {
return new class extends Client {
public function get_tracker_id() {
return 'pa-test-tracker-id';
}
Expand Down
2 changes: 2 additions & 0 deletions tests/integration/AdminBarTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ public function testAdminBarNode() {
}

wp_set_current_user( 1 );
$user = wp_get_current_user();
$user->add_role( 'administrator' );
$admin_bar = new WP_Admin_Bar();
$class->admin_bar_node( $admin_bar );
$this->assertNotEmpty( $admin_bar->get_node( 'plausible-analytics' ) );
Expand Down
Loading