SensorPro admin page. * * @package SensorPro */ if ( ! defined( 'ABSPATH' ) ) { exit; } /** * Settings page. */ class SensorPro_Settings { /** Fields whose saved value is never printed back. */ const SECRET_FIELDS = array( 'api_key', 'api_password' ); /** * Hooks. */ public static function init() { add_action( 'admin_menu', array( __CLASS__, 'menu' ) ); add_action( 'admin_init', array( __CLASS__, 'register' ) ); add_action( 'admin_enqueue_scripts', array( __CLASS__, 'assets' ) ); add_action( 'wp_ajax_sensorpro_test_connection', array( __CLASS__, 'ajax_test' ) ); } /** * Menu item. */ public static function menu() { add_options_page( __( 'SensorPro', 'sensorpro' ), __( 'SensorPro', 'sensorpro' ), 'manage_options', 'sensorpro', array( __CLASS__, 'page' ) ); } /** * Admin assets. * * @param string $hook Hook suffix. */ public static function assets( $hook ) { if ( 'settings_page_sensorpro' !== $hook ) { return; } wp_enqueue_style( 'sensorpro-admin', SENSORPRO_URL . 'assets/css/admin.css', array(), SENSORPRO_VERSION ); wp_enqueue_script( 'sensorpro-admin', SENSORPRO_URL . 'assets/js/admin.js', array(), SENSORPRO_VERSION, true ); wp_localize_script( 'sensorpro-admin', 'SensorProAdmin', array( 'ajaxUrl' => admin_url( 'admin-ajax.php' ), 'nonce' => wp_create_nonce( 'sensorpro_test_connection' ), 'testing' => __( 'Testing…', 'sensorpro' ), 'failed' => __( 'Request failed.', 'sensorpro' ), ) ); } /** * Register setting. */ public static function register() { register_setting( 'sensorpro', SENSORPRO_OPTION, array( 'type' => 'array', 'sanitize_callback' => array( __CLASS__, 'sanitize' ), 'default' => sensorpro_default_settings(), ) ); } /** * Sanitize settings. Blank secret fields keep the stored value. * * @param array $in Raw input (already unslashed by options.php). * @return array */ public static function sanitize( $in ) { $old = sensorpro_get_settings(); $in = is_array( $in ) ? $in : array(); $out = $old; $base = isset( $in['api_base'] ) ? esc_url_raw( trim( sanitize_text_field( $in['api_base'] ) ) ) : $old['api_base']; if ( $base && 0 !== strpos( $base, 'https://' ) ) { add_settings_error( SENSORPRO_OPTION, 'base', __( 'The API URL must start with https://.', 'sensorpro' ) ); $base = $old['api_base']; } $out['api_base'] = $base ? untrailingslashit( $base ) : sensorpro_default_settings()['api_base']; foreach ( self::SECRET_FIELDS as $k ) { if ( ! empty( $in[ $k . '_clear' ] ) ) { $out[ $k ] = ''; } elseif ( isset( $in[ $k ] ) && '' !== sanitize_text_field( $in[ $k ] ) ) { $out[ $k ] = sanitize_text_field( $in[ $k ] ); } } foreach ( array( 'organization', 'api_user', 'import_name', 'button_text' ) as $k ) { $out[ $k ] = isset( $in[ $k ] ) ? sanitize_text_field( $in[ $k ] ) : ''; } $out['tags'] = isset( $in['tags'] ) ? implode( ', ', SensorPro_Form::parse_tags( sanitize_text_field( $in['tags'] ) ) ) : ''; unset( $out['signup_form_id'] ); // Setting removed before 1.0.0. foreach ( array( 'send_welcome', 'show_first_name', 'show_last_name', 'require_names', 'consent_enabled' ) as $k ) { $out[ $k ] = empty( $in[ $k ] ) ? 0 : 1; } $out['consent_text'] = isset( $in['consent_text'] ) ? wp_kses( $in['consent_text'], array( 'a' => array( 'href' => array(), 'target' => array(), 'rel' => array() ), 'strong' => array(), 'em' => array() ) ) : ''; $out['success_message'] = isset( $in['success_message'] ) ? sanitize_textarea_field( $in['success_message'] ) : ''; $out['redirect_url'] = isset( $in['redirect_url'] ) ? esc_url_raw( trim( sanitize_text_field( $in['redirect_url'] ) ) ) : ''; $cf = isset( $in['consent_field'] ) ? sanitize_text_field( $in['consent_field'] ) : ''; $out['consent_field'] = in_array( $cf, self::consent_fields(), true ) ? $cf : ''; delete_transient( SensorPro_API::TOKEN_TRANSIENT ); return $out; } /** * Contact fields that may hold the consent record. * * @return string[] */ public static function consent_fields() { $f = array(); for ( $i = 2; $i <= 15; $i++ ) { $f[] = 'UserChar' . $i; } return $f; } /** * Masked hint for a stored secret. * * @param string $v Secret. * @return string */ private static function mask( $v ) { if ( '' === (string) $v ) { return __( 'Not set', 'sensorpro' ); } /* translators: %s: last 4 characters */ return sprintf( __( 'Saved (ends in …%s). Leave blank to keep.', 'sensorpro' ), substr( $v, -4 ) ); } /** * AJAX: test connection. */ public static function ajax_test() { check_ajax_referer( 'sensorpro_test_connection', 'nonce' ); if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => __( 'Not allowed.', 'sensorpro' ) ), 403 ); } delete_transient( SensorPro_API::TOKEN_TRANSIENT ); $api = new SensorPro_API(); $t = $api->signin( true ); if ( is_wp_error( $t ) ) { wp_send_json_error( array( 'message' => $t->get_error_message() ) ); } wp_send_json_success( array( 'message' => __( 'Connected. SensorPro accepted the credentials from this server.', 'sensorpro' ) ) ); } /** * Render page. */ public static function page() { if ( ! current_user_can( 'manage_options' ) ) { return; } $s = sensorpro_get_settings(); $n = SENSORPRO_OPTION; ?>