Newer
Older
wordpress-ojs-pugin / includes / class-settings.php
<?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
    }
}