| @@ -28,8 +28,10 @@ | ||
| 28 | 28 | * @return void |
| 29 | 29 | */ |
| 30 | 30 | public function __construct() { |
| 31 | 31 | add_action( 'admin_menu', array($this, 'add_menu') ); |
| 32 | + add_action( 'admin_menu', array($this, 'add_settings_submenu'), 99 ); | |
| 33 | + // Add Settings last | |
| 32 | 34 | add_action( 'rest_api_init', array($this, 'rest_api_init') ); |
| 33 | 35 | } |
| 34 | 36 | |
| 35 | 37 | public function add_menu() { |
| @@ -41,8 +43,14 @@ | ||
| 41 | 43 | array($this, 'render_settings'), |
| 42 | 44 | 'dashicons-lock', |
| 43 | 45 | 85 |
| 44 | 46 | ); |
| 47 | + } | |
| 48 | + | |
| 49 | + /** | |
| 50 | + * Add Settings submenu at the end (priority 99) | |
| 51 | + */ | |
| 52 | + public function add_settings_submenu() { | |
| 45 | 53 | $settings_suffix = add_submenu_page( |
| 46 | 54 | 'passster', |
| 47 | 55 | __( 'Options', 'content-protector' ), |
| 48 | 56 | __( 'Settings', 'content-protector' ), |
| @@ -69,14 +77,25 @@ | ||
| 69 | 77 | PASSSTER_VERSION, |
| 70 | 78 | true |
| 71 | 79 | ); |
| 72 | 80 | $options = get_option( 'passster' ); |
| 81 | + // Freemius | |
| 82 | + $fs_slug = 'content-protector'; | |
| 83 | + $fs_id = '1938'; | |
| 84 | + $fs_affix = \passster_fs()->get_unique_affix(); | |
| 73 | 85 | $args = array( |
| 74 | - 'screen' => 'passster-settings', | |
| 75 | - 'version' => PASSSTER_VERSION, | |
| 76 | - 'logo' => PASSSTER_URL . '/assets/admin/passster-logo.svg', | |
| 77 | - 'is_pro' => \passster_fs()->is_plan_or_trial__premium_only( 'pro' ), | |
| 86 | + 'screen' => 'passster-settings', | |
| 87 | + 'version' => PASSSTER_VERSION, | |
| 88 | + 'logo' => PASSSTER_URL . '/assets/admin/passster-logo.svg', | |
| 89 | + 'is_pro' => \passster_fs()->is_plan_or_trial__premium_only( 'pro' ), | |
| 90 | + 'is_premium_build' => \passster_fs()->is_premium(), | |
| 91 | + 'account_url' => admin_url( 'admin.php?page=' . $fs_slug . '-account' ), | |
| 92 | + 'activation_url' => '#', | |
| 93 | + 'upgrade_url' => \passster_fs()->get_upgrade_url(), | |
| 94 | + 'fs_affix' => $fs_affix, | |
| 78 | 95 | ); |
| 96 | + // Add Freemius license activation dialog on settings page | |
| 97 | + add_action( 'admin_footer', array($this, 'add_license_activation_dialog') ); | |
| 79 | 98 | if ( isset( $options['global_protection_id'] ) ) { |
| 80 | 99 | $args['global_edit_url'] = admin_url( 'post.php?post=' . esc_html( $options['global_protection_id'] ) . '&action=edit', 'https' ); |
| 81 | 100 | } |
| 82 | 101 | wp_localize_script( 'passster-settings', 'options', $args ); |
| @@ -92,8 +111,24 @@ | ||
| 92 | 111 | <div id="passster-settings"></div> |
| 93 | 112 | <?php |
| 94 | 113 | } |
| 95 | 114 | |
| 115 | + /** | |
| 116 | + * Add Freemius license activation dialog to settings page. | |
| 117 | + */ | |
| 118 | + public function add_license_activation_dialog() { | |
| 119 | + $fs = \passster_fs(); | |
| 120 | + // On the free build the AJAX handler is not registered by Freemius, so the dialog is useless. | |
| 121 | + if ( !$fs->is_premium() ) { | |
| 122 | + return; | |
| 123 | + } | |
| 124 | + $vars = array( | |
| 125 | + 'id' => $fs->get_id(), | |
| 126 | + ); | |
| 127 | + fs_require_template( 'forms/license-activation.php', $vars ); | |
| 128 | + fs_require_template( 'forms/resend-key.php', $vars ); | |
| 129 | + } | |
| 130 | + | |
| 96 | 131 | public function rest_api_init() { |
| 97 | 132 | register_rest_route( 'passster/v1', '/settings', array( |
| 98 | 133 | 'methods' => 'GET', |
| 99 | 134 | 'callback' => [$this, 'get_settings'], |
| @@ -176,13 +211,27 @@ | ||
| 176 | 211 | } |
| 177 | 212 | |
| 178 | 213 | public function save_settings( $request ) { |
| 179 | 214 | if ( $request->get_params() ) { |
| 180 | - $options = sanitize_option( 'passster', $request->get_params() ); | |
| 215 | + $options = $request->get_params(); | |
| 181 | 216 | foreach ( $options as $key => $value ) { |
| 182 | - if ( $key !== 'exclude_pages' && !is_array( $value ) ) { | |
| 183 | - $options[$key] = sanitize_text_field( $value ); | |
| 217 | + // Allow HTML in instruction field (links, basic formatting) | |
| 218 | + if ( 'instruction' === $key ) { | |
| 219 | + $options[$key] = wp_kses_post( $value ); | |
| 220 | + continue; | |
| 184 | 221 | } |
| 222 | + // Allow HTML in error message field too | |
| 223 | + if ( 'error' === $key ) { | |
| 224 | + $options[$key] = wp_kses_post( $value ); | |
| 225 | + continue; | |
| 226 | + } | |
| 227 | + // Arrays (like exclude_pages) - sanitize each item | |
| 228 | + if ( is_array( $value ) ) { | |
| 229 | + $options[$key] = array_map( 'sanitize_text_field', $value ); | |
| 230 | + continue; | |
| 231 | + } | |
| 232 | + // Everything else - sanitize as text | |
| 233 | + $options[$key] = sanitize_text_field( $value ); | |
| 185 | 234 | } |
| 186 | 235 | update_option( 'passster', $options ); |
| 187 | 236 | } |
| 188 | 237 | return wp_json_encode( [ |