<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class WP_OJS_SSO_Settings {
private static $instance = null;
public static function instance() {
if ( null === self::$instance ) {
self::$instance = new self();
}
return self::$instance;
}
private function __construct() {
add_action( 'admin_menu', [ $this, 'add_menu' ] );
add_action( 'admin_init', [ $this, 'register_settings' ] );
add_filter( 'plugin_action_links_' . WP_OJS_SSO_BASENAME, [ $this, 'action_links' ] );
}
public function add_menu() {
add_options_page(
__( 'OJS SSO Bridge', 'wp-ojs-sso-bridge' ),
__( 'OJS SSO Bridge', 'wp-ojs-sso-bridge' ),
'manage_options',
'wp-ojs-sso-bridge',
[ $this, 'render_page' ]
);
}
public function action_links( $links ) {
$url = admin_url( 'options-general.php?page=wp-ojs-sso-bridge' );
array_unshift( $links, sprintf( '<a href="%s">%s</a>', esc_url( $url ), esc_html__( 'Settings', 'wp-ojs-sso-bridge' ) ) );
return $links;
}
public function register_settings() {
register_setting( 'wp_ojs_sso_bridge', 'wp_ojs_sso_bridge_settings', [
'sanitize_callback' => [ $this, 'sanitize' ],
] );
// --- OIDC Section ---
add_settings_section( 'oidc', __( 'OpenID Connect', 'wp-ojs-sso-bridge' ), '__return_false', 'wp-ojs-sso-bridge' );
$this->add_field( 'client_id', __( 'OJS Client ID', 'wp-ojs-sso-bridge' ), 'text', 'oidc', 'ojs-arstexnica' );
$this->add_field( 'client_secret', __( 'OJS Client Secret', 'wp-ojs-sso-bridge' ), 'text', 'oidc' );
$this->add_field( 'redirect_uri', __( 'OJS Redirect URI', 'wp-ojs-sso-bridge' ), 'url', 'oidc' );
$this->add_field( 'claim_name', __( 'OIDC Claim Name', 'wp-ojs-sso-bridge' ), 'text', 'oidc', 'subscription_active' );
// --- User Meta Section ---
add_settings_section( 'meta', __( 'User Meta', 'wp-ojs-sso-bridge' ), '__return_false', 'wp-ojs-sso-bridge' );
$this->add_field( 'user_meta_key', __( 'Subscription Meta Key', 'wp-ojs-sso-bridge' ), 'text', 'meta', 'ojs_subscription_active' );
$this->add_field( 'user_meta_label', __( 'Subscription Label', 'wp-ojs-sso-bridge' ), 'text', 'meta', __( 'OJS Subscription Active', 'wp-ojs-sso-bridge' ) );
// --- Registration Section ---
add_settings_section( 'registration', __( 'Registration Form', 'wp-ojs-sso-bridge' ), '__return_false', 'wp-ojs-sso-bridge' );
$this->add_field( 'enable_registration_checkbox', __( 'Enable subscription request at registration', 'wp-ojs-sso-bridge' ), 'checkbox', 'registration' );
$this->add_field( 'registration_checkbox_text', __( 'Checkbox label', 'wp-ojs-sso-bridge' ), 'text', 'registration', __( 'I want to subscribe to the journal', 'wp-ojs-sso-bridge' ) );
$this->add_field( 'registration_description', __( 'Description below checkbox (HTML allowed)', 'wp-ojs-sso-bridge' ), 'textarea', 'registration', __( 'Your subscription will be activated after verification by an administrator.', 'wp-ojs-sso-bridge' ) );
$this->add_field( 'notify_admin_on_request', __( 'Notify admin on subscription request', 'wp-ojs-sso-bridge' ), 'checkbox', 'registration' );
// --- Cleanup Section ---
add_settings_section( 'cleanup', __( 'Uninstall', 'wp-ojs-sso-bridge' ), '__return_false', 'wp-ojs-sso-bridge' );
$this->add_field( 'cleanup_on_uninstall', __( 'Remove all user data on uninstall', 'wp-ojs-sso-bridge' ), 'checkbox', 'cleanup' );
}
private function add_field( $id, $title, $type, $section, $default = '' ) {
add_settings_field(
$id,
$title,
[ $this, 'render_field' ],
'wp-ojs-sso-bridge',
$section,
[ 'id' => $id, 'type' => $type, 'default' => $default ]
);
}
public function render_field( $args ) {
$opts = WP_OJS_SSO_Plugin::get_option();
$id = $args['id'];
$type = $args['type'];
$value = $opts[ $id ] ?? $args['default'];
$name = "wp_ojs_sso_bridge_settings[{$id}]";
switch ( $type ) {
case 'checkbox':
printf(
'<input type="checkbox" id="%1$s" name="%2$s" value="1" %3$s />',
esc_attr( $id ),
esc_attr( $name ),
checked( $value, '1', false )
);
break;
case 'textarea':
printf(
'<textarea id="%1$s" name="%2$s" class="large-text" rows="5">%3$s</textarea>',
esc_attr( $id ),
esc_attr( $name ),
esc_textarea( $value )
);
if ( 'registration_description' === $id ) {
echo '<p class="description">' . esc_html__( 'You can use simple HTML (paragraphs, lists, links, bold, line breaks) for the text shown on the registration screen.', 'wp-ojs-sso-bridge' ) . '</p>';
}
break;
case 'url':
printf(
'<input type="url" id="%1$s" name="%2$s" value="%3$s" class="regular-text" />',
esc_attr( $id ),
esc_attr( $name ),
esc_url( $value )
);
break;
default:
printf(
'<input type="text" id="%1$s" name="%2$s" value="%3$s" class="regular-text" />',
esc_attr( $id ),
esc_attr( $name ),
esc_attr( $value )
);
}
}
public function sanitize( $input ) {
$clean = [];
$clean['client_id'] = sanitize_text_field( $input['client_id'] ?? '' );
$clean['client_secret'] = sanitize_text_field( $input['client_secret'] ?? '' );
$clean['redirect_uri'] = esc_url_raw( $input['redirect_uri'] ?? '' );
$clean['claim_name'] = sanitize_key( $input['claim_name'] ?? 'subscription_active' );
$clean['user_meta_key'] = sanitize_key( $input['user_meta_key'] ?? 'ojs_subscription_active' );
$clean['user_meta_label'] = sanitize_text_field( $input['user_meta_label'] ?? '' );
$clean['enable_registration_checkbox'] = ! empty( $input['enable_registration_checkbox'] ) ? '1' : '';
$clean['registration_checkbox_text'] = sanitize_text_field( $input['registration_checkbox_text'] ?? '' );
$clean['registration_description'] = wp_kses_post( trim( (string) ( $input['registration_description'] ?? '' ) ) );
$clean['notify_admin_on_request'] = ! empty( $input['notify_admin_on_request'] ) ? '1' : '';
$clean['cleanup_on_uninstall'] = ! empty( $input['cleanup_on_uninstall'] ) ? '1' : '';
return $clean;
}
public function render_page() {
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
?>
<div class="wrap">
<h1><?php echo esc_html( get_admin_page_title() ); ?></h1>
<form method="post" action="options.php">
<?php
settings_fields( 'wp_ojs_sso_bridge' );
do_settings_sections( 'wp-ojs-sso-bridge' );
submit_button();
?>
</form>
<?php $this->render_generate_secret_button(); ?>
</div>
<?php
}
private function render_generate_secret_button() {
?>
<script>
document.addEventListener('DOMContentLoaded', function() {
var secretField = document.getElementById('client_secret');
if (!secretField) return;
var btn = document.createElement('button');
btn.type = 'button';
btn.className = 'button button-secondary';
btn.textContent = <?php echo wp_json_encode( __( 'Generate Secret', 'wp-ojs-sso-bridge' ) ); ?>;
btn.style.marginLeft = '8px';
btn.addEventListener('click', function() {
var arr = new Uint8Array(32);
crypto.getRandomValues(arr);
secretField.value = Array.from(arr, function(b) { return b.toString(16).padStart(2, '0'); }).join('');
});
secretField.parentNode.insertBefore(btn, secretField.nextSibling);
});
</script>
<?php
}
}