<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class WP_OJS_SSO_Profile {
private static $instance = null;
public static function instance() {
if ( null === self::$instance ) {
self::$instance = new self();
}
return self::$instance;
}
private function __construct() {
// Front-end profile (user's own)
add_action( 'show_user_profile', [ $this, 'render_user_fields' ] );
// Admin editing another user's profile
add_action( 'edit_user_profile', [ $this, 'render_admin_fields' ] );
add_action( 'personal_options_update', [ $this, 'save_user_fields' ] );
add_action( 'edit_user_profile_update', [ $this, 'save_admin_fields' ] );
add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_admin_scripts' ] );
}
public function enqueue_admin_scripts( $hook ) {
if ( ! in_array( $hook, [ 'user-edit.php', 'profile.php' ], true ) ) {
return;
}
wp_enqueue_script(
'wp-ojs-sso-conditional',
WP_OJS_SSO_URL . 'assets/js/conditional-fields.js',
[],
WP_OJS_SSO_VERSION,
true
);
wp_enqueue_style(
'wp-ojs-sso-admin',
WP_OJS_SSO_URL . 'assets/css/admin-styles.css',
[],
WP_OJS_SSO_VERSION
);
// Localized strings for the deactivation confirm dialog
wp_localize_script( 'wp-ojs-sso-conditional', 'wpOjsSsoBridge', [
'confirmDeactivation' => esc_html__(
'Deactivating the subscription will immediately disconnect this user from WordPress and revoke their access to the journal on OJS. Continue?',
'wp-ojs-sso-bridge'
),
] );
// Ensure profile form supports file uploads
add_action( 'admin_footer', function() {
echo '<script>var f=document.getElementById("your-profile");if(f)f.enctype="multipart/form-data";</script>';
} );
}
/**
* Render subscription fields on the user's own profile page.
* Users can request subscription or edit their own data, but cannot toggle active status.
*/
public function render_user_fields( $user ) {
$requested = (bool) get_user_meta( $user->ID, 'ojs_subscription_requested', true );
$meta_key = WP_OJS_SSO_Plugin::get_option( 'user_meta_key', 'ojs_subscription_active' );
$active = (bool) get_user_meta( $user->ID, $meta_key, true );
if ( ! $active && ! $requested && ! WP_OJS_SSO_Plugin::get_option( 'enable_registration_checkbox' ) ) {
return; // subscription request not enabled and user hasn't requested
}
echo '<h3>' . esc_html__( 'Journal Subscription', 'wp-ojs-sso-bridge' ) . '</h3>';
echo '<table class="form-table" role="presentation">';
wp_nonce_field( 'wp_ojs_sso_save_profile', '_wp_ojs_sso_profile_nonce' );
// Status display
echo '<tr><th>' . esc_html__( 'Status', 'wp-ojs-sso-bridge' ) . '</th><td>';
if ( $active ) {
echo '<span style="color:#46b450;font-weight:600;">' . esc_html__( 'Active', 'wp-ojs-sso-bridge' ) . '</span>';
} elseif ( $requested ) {
echo '<span style="color:#ffb900;font-weight:600;">' . esc_html__( 'Requested – pending approval', 'wp-ojs-sso-bridge' ) . '</span>';
} else {
echo esc_html__( 'Not subscribed', 'wp-ojs-sso-bridge' );
}
echo '</td></tr>';
if ( ! $requested && ! $active ) {
// Offer to subscribe
$checkbox_text = WP_OJS_SSO_Plugin::get_option(
'registration_checkbox_text',
__( 'I want to subscribe to the journal', 'wp-ojs-sso-bridge' )
);
echo '<tr><th></th><td>';
echo '<label><input type="checkbox" name="ojs_subscription_requested" id="ojs_subscription_requested" value="1" /> ';
echo esc_html( $checkbox_text );
echo '</label></td></tr>';
}
// Show subscription fields (editable) if requested or active
if ( $requested || $active ) {
$this->render_subscription_data_rows( $user, false );
} else {
// Hidden block that shows when checkbox is toggled
echo '</table>';
echo '<div id="ojs-subscription-fields" style="display:none;">';
echo '<table class="form-table" role="presentation">';
$this->render_subscription_data_rows( $user, false );
echo '</table></div>';
echo '<table class="form-table" role="presentation" style="display:none;">'; // close outer table cleanly
}
echo '</table>';
}
/**
* Render fields for admin editing another user.
* Admin can see all data, toggle active status, and download documents.
*/
public function render_admin_fields( $user ) {
$meta_key = WP_OJS_SSO_Plugin::get_option( 'user_meta_key', 'ojs_subscription_active' );
$active = (bool) get_user_meta( $user->ID, $meta_key, true );
$requested = (bool) get_user_meta( $user->ID, 'ojs_subscription_requested', true );
echo '<h3>' . esc_html__( 'Journal Subscription', 'wp-ojs-sso-bridge' ) . '</h3>';
echo '<table class="form-table" role="presentation">';
wp_nonce_field( 'wp_ojs_sso_save_meta', '_wp_ojs_sso_nonce' );
// Active toggle (admin only)
$label = WP_OJS_SSO_Plugin::get_option( 'user_meta_label', __( 'OJS Subscription Active', 'wp-ojs-sso-bridge' ) );
echo '<tr><th><label for="' . esc_attr( $meta_key ) . '">' . esc_html( $label ) . '</label></th><td>';
printf(
'<input type="checkbox" name="%1$s" id="%1$s" value="1" %2$s />',
esc_attr( $meta_key ),
checked( $active, true, false )
);
if ( $requested && ! $active ) {
echo ' <span class="description" style="color:#ffb900;">' . esc_html__( '(user has requested subscription)', 'wp-ojs-sso-bridge' ) . '</span>';
}
echo '</td></tr>';
$this->render_subscription_data_rows( $user, true );
echo '</table>';
}
private function render_subscription_data_rows( $user, $is_admin ) {
$fields = WP_OJS_SSO_Subscription_Fields::get_fields();
// First/last name
echo '<tr><th><label for="first_name">' . esc_html__( 'First Name', 'wp-ojs-sso-bridge' ) . ' *</label></th><td>';
printf( '<input type="text" name="first_name" id="first_name" value="%s" class="regular-text" />', esc_attr( $user->first_name ) );
echo '</td></tr>';
echo '<tr><th><label for="last_name">' . esc_html__( 'Last Name', 'wp-ojs-sso-bridge' ) . ' *</label></th><td>';
printf( '<input type="text" name="last_name" id="last_name" value="%s" class="regular-text" />', esc_attr( $user->last_name ) );
echo '</td></tr>';
foreach ( $fields as $key => $field ) {
$mkey = $field['meta_key'] ?? $key;
$value = get_user_meta( $user->ID, $mkey, true );
echo '<tr><th>';
echo '<label for="' . esc_attr( $key ) . '">' . esc_html( $field['label'] );
if ( ! empty( $field['required'] ) ) {
echo ' *';
}
echo '</label></th><td>';
if ( 'file' === $field['type'] ) {
$show_name = '';
$has_file = false;
if ( 'ojs_bonifico_receipt' === $key && class_exists( 'WP_OJS_SSO_Subscription_Media' ) ) {
if ( WP_OJS_SSO_Subscription_Media::get_attachment_id( $user->ID, WP_OJS_SSO_Subscription_Media::KIND_BONIFICO ) > 0 ) {
$has_file = true;
$show_name = WP_OJS_SSO_Subscription_Media::get_file_label( $user->ID, WP_OJS_SSO_Subscription_Media::KIND_BONIFICO );
}
} elseif ( 'ojs_student_document' === $key && class_exists( 'WP_OJS_SSO_Subscription_Media' ) ) {
if ( WP_OJS_SSO_Subscription_Media::get_attachment_id( $user->ID, WP_OJS_SSO_Subscription_Media::KIND_CERTIFICATO ) > 0 ) {
$has_file = true;
$show_name = WP_OJS_SSO_Subscription_Media::get_file_label( $user->ID, WP_OJS_SSO_Subscription_Media::KIND_CERTIFICATO );
} elseif ( is_string( $value ) && $value && is_file( $value ) ) {
$has_file = true;
$show_name = wp_basename( $value );
}
}
if ( $has_file && $show_name ) {
echo '<p>' . esc_html( $show_name );
if ( $is_admin && 'ojs_student_document' === $key && is_string( $value ) && $value && is_file( $value ) && ! is_numeric( $value ) ) {
$url = WP_OJS_SSO_File_Upload::get_admin_download_url( $user->ID );
echo ' — <a href="' . esc_url( $url ) . '">' . esc_html__( 'Download', 'wp-ojs-sso-bridge' ) . '</a>';
} elseif ( $is_admin && ( 'ojs_bonifico_receipt' === $key || ( 'ojs_student_document' === $key && is_numeric( $value ) ) ) ) {
$kind = ( 'ojs_bonifico_receipt' === $key ) ? WP_OJS_SSO_Subscription_Media::KIND_BONIFICO : WP_OJS_SSO_Subscription_Media::KIND_CERTIFICATO;
$elink = WP_OJS_SSO_Subscription_Media::get_edit_link( $user->ID, $kind );
if ( $elink ) {
echo ' — <a href="' . esc_url( $elink ) . '">' . esc_html__( 'Open in Media', 'wp-ojs-sso-bridge' ) . '</a>';
}
} elseif ( ! $is_admin && class_exists( 'WP_OJS_SSO_Subscription_Media' ) ) {
$aid = 0;
if ( 'ojs_bonifico_receipt' === $key ) {
$aid = WP_OJS_SSO_Subscription_Media::get_attachment_id( $user->ID, WP_OJS_SSO_Subscription_Media::KIND_BONIFICO );
} elseif ( 'ojs_student_document' === $key && is_numeric( $value ) ) {
$aid = (int) $value;
}
if ( $aid > 0 ) {
$u = wp_get_attachment_url( $aid );
if ( $u ) {
echo ' — <a href="' . esc_url( $u ) . '" target="_blank" rel="noopener noreferrer">' . esc_html__( 'View file', 'wp-ojs-sso-bridge' ) . '</a>';
}
}
}
echo '</p>';
}
printf(
'<input type="file" name="%1$s" id="%1$s" accept="%2$s" />',
esc_attr( $key ),
esc_attr( $field['accept'] ?? '' )
);
echo '<p class="description">' . esc_html__( 'Upload a new file to replace the existing one.', 'wp-ojs-sso-bridge' ) . '</p>';
} else {
WP_OJS_SSO_Subscription_Fields::render_field( $key, $field, $value );
}
echo '</td></tr>';
}
}
public function save_user_fields( $user_id ) {
if ( ! wp_verify_nonce( $_POST['_wp_ojs_sso_profile_nonce'] ?? '', 'wp_ojs_sso_save_profile' ) ) {
return;
}
// User requesting subscription from profile
if ( ! empty( $_POST['ojs_subscription_requested'] ) ) {
$was_requested = (bool) get_user_meta( $user_id, 'ojs_subscription_requested', true );
update_user_meta( $user_id, 'ojs_subscription_requested', '1' );
$errors = WP_OJS_SSO_Subscription_Fields::validate( $_POST, $_FILES, $user_id );
if ( empty( $errors ) ) {
WP_OJS_SSO_Subscription_Fields::save_fields( $user_id, $_POST );
if ( ! empty( $_FILES['ojs_student_document']['name'] ) ) {
WP_OJS_SSO_File_Upload::handle_upload( $user_id );
}
if ( ! empty( $_FILES['ojs_bonifico_receipt']['name'] ) && class_exists( 'WP_OJS_SSO_Subscription_Media' ) ) {
WP_OJS_SSO_Subscription_Media::handle_upload( $user_id, 'ojs_bonifico_receipt', WP_OJS_SSO_Subscription_Media::KIND_BONIFICO );
}
// Notify admin for new request
if ( ! $was_requested && WP_OJS_SSO_Plugin::get_option( 'notify_admin_on_request' ) ) {
$user = get_userdata( $user_id );
wp_mail(
get_option( 'admin_email' ),
sprintf( __( '[%s] New journal subscription request', 'wp-ojs-sso-bridge' ), get_bloginfo( 'name' ) ),
sprintf(
__( "User \"%1\$s\" (%2\$s) has requested a journal subscription from their profile.\n\nReview: %3\$s", 'wp-ojs-sso-bridge' ),
$user->user_login,
$user->user_email,
admin_url( 'users.php?ojs_sub_filter=requested' )
)
);
}
}
}
// If already subscribed, allow editing fields
$meta_key = WP_OJS_SSO_Plugin::get_option( 'user_meta_key', 'ojs_subscription_active' );
if ( (bool) get_user_meta( $user_id, $meta_key, true ) ) {
WP_OJS_SSO_Subscription_Fields::save_fields( $user_id, $_POST );
if ( ! empty( $_FILES['ojs_student_document']['name'] ) ) {
WP_OJS_SSO_File_Upload::handle_upload( $user_id );
}
if ( ! empty( $_FILES['ojs_bonifico_receipt']['name'] ) && class_exists( 'WP_OJS_SSO_Subscription_Media' ) ) {
WP_OJS_SSO_Subscription_Media::handle_upload( $user_id, 'ojs_bonifico_receipt', WP_OJS_SSO_Subscription_Media::KIND_BONIFICO );
}
}
}
public function save_admin_fields( $user_id ) {
if ( ! current_user_can( 'edit_users' ) ) {
return;
}
if ( ! wp_verify_nonce( $_POST['_wp_ojs_sso_nonce'] ?? '', 'wp_ojs_sso_save_meta' ) ) {
return;
}
$meta_key = WP_OJS_SSO_Plugin::get_option( 'user_meta_key', 'ojs_subscription_active' );
$old_value = (bool) get_user_meta( $user_id, $meta_key, true );
$new_value = ! empty( $_POST[ $meta_key ] );
update_user_meta( $user_id, $meta_key, $new_value ? '1' : '' );
// Session invalidation on deactivation
if ( $old_value && ! $new_value ) {
$sessions = WP_Session_Tokens::get_instance( $user_id );
$sessions->destroy_all();
}
do_action( 'wp_ojs_sso_subscription_changed', $user_id, $new_value );
// Save subscription data fields
WP_OJS_SSO_Subscription_Fields::save_fields( $user_id, $_POST );
if ( ! empty( $_FILES['ojs_student_document']['name'] ) ) {
WP_OJS_SSO_File_Upload::handle_upload( $user_id );
}
if ( ! empty( $_FILES['ojs_bonifico_receipt']['name'] ) && class_exists( 'WP_OJS_SSO_Subscription_Media' ) ) {
WP_OJS_SSO_Subscription_Media::handle_upload( $user_id, 'ojs_bonifico_receipt', WP_OJS_SSO_Subscription_Media::KIND_BONIFICO );
}
}
}