<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class WP_OJS_SSO_Subscription_Fields {
private static $instance = null;
public static function instance() {
if ( null === self::$instance ) {
self::$instance = new self();
}
return self::$instance;
}
private function __construct() {}
public static function get_fields() {
return [
'ojs_birthplace' => [
'label' => __( 'Place of birth', 'wp-ojs-sso-bridge' ),
'type' => 'text',
'required' => true,
],
'ojs_birthdate' => [
'label' => __( 'Date of birth', 'wp-ojs-sso-bridge' ),
'type' => 'date',
'required' => true,
],
'ojs_fiscal_code' => [
'label' => __( 'Fiscal Code', 'wp-ojs-sso-bridge' ),
'type' => 'text',
'required' => true,
'pattern' => '[A-Za-z0-9]{16}',
'maxlength' => 16,
],
'ojs_shipping_address' => [
'label' => __( 'Shipping address for the journal', 'wp-ojs-sso-bridge' ),
'type' => 'textarea',
'required' => true,
],
'ojs_membership_type' => [
'label' => __( 'Membership type', 'wp-ojs-sso-bridge' ),
'type' => 'radio',
'required' => true,
'options' => [
'ordinary' => __( 'Ordinary member (no TugBoat subscription)', 'wp-ojs-sso-bridge' ),
'ordinary_tugboat' => __( 'Ordinary member with TugBoat subscription', 'wp-ojs-sso-bridge' ),
'student' => __( 'Student member (document required)', 'wp-ojs-sso-bridge' ),
'student_junior' => __( 'Junior student member (document required)', 'wp-ojs-sso-bridge' ),
'institutional' => __( 'Institutional member', 'wp-ojs-sso-bridge' ),
],
],
'ojs_student_document' => [
'label' => __( 'Student certificate (PDF, JPG or PNG, max 10 MB)', 'wp-ojs-sso-bridge' ),
'type' => 'file',
'required' => false, // conditionally required via JS + server validation
'accept' => '.pdf,.jpg,.jpeg,.png',
'meta_key' => 'ojs_student_document', // may store attachment ID or legacy path
'conditional' => [ 'ojs_membership_type' => [ 'student', 'student_junior' ] ],
],
'ojs_bonifico_receipt' => [
'label' => __( 'Bank transfer receipt (PDF, JPG or PNG, max 10 MB)', 'wp-ojs-sso-bridge' ),
'type' => 'file',
'required' => false, // required in validate() for subscription requests
'accept' => '.pdf,.jpg,.jpeg,.png',
'meta_key' => 'ojs_bonifico_attachment_id', // file input name ojs_bonifico_receipt, meta stores attachment id
],
'ojs_consent_guit_soci' => [
'label' => __( 'I consent to being added to the guit-soci mailing list for institutional communications (mandatory).', 'wp-ojs-sso-bridge' ),
'type' => 'checkbox',
'required' => true,
],
'ojs_consent_guit_members' => [
'label' => __( 'I consent to being added to the guit-members mailing list for group activity communications.', 'wp-ojs-sso-bridge' ),
'type' => 'radio',
'required' => true,
'options' => [
'1' => __( 'I consent', 'wp-ojs-sso-bridge' ),
'0' => __( 'I do not consent', 'wp-ojs-sso-bridge' ),
],
],
'ojs_consent_privacy' => [
'label' => __( 'I consent to the processing of personal data provided through this form for the institutional purposes of the association.', 'wp-ojs-sso-bridge' ),
'type' => 'checkbox',
'required' => true,
],
];
}
public static function render_field( $key, $field, $value = '' ) {
$required_attr = '';
$data_attr = '';
if ( ! empty( $field['required'] ) ) {
$required_attr = ' data-conditional-required="1"';
}
if ( ! empty( $field['conditional'] ) ) {
$data_attr = sprintf( ' data-show-when="%s"', esc_attr( wp_json_encode( $field['conditional'] ) ) );
}
$wrapper_id = 'ojs-field-' . esc_attr( $key );
$is_conditional = ! empty( $field['conditional'] );
$style = $is_conditional ? ' style="display:none;"' : '';
echo '<div id="' . esc_attr( $wrapper_id ) . '" class="ojs-field-wrapper"' . $style . $data_attr . '>';
echo '<label for="' . esc_attr( $key ) . '">';
echo esc_html( $field['label'] );
if ( ! empty( $field['required'] ) ) {
echo ' <span class="description">*</span>';
}
echo '</label><br/>';
switch ( $field['type'] ) {
case 'text':
printf(
'<input type="text" name="%1$s" id="%1$s" value="%2$s" class="input" %3$s %4$s %5$s />',
esc_attr( $key ),
esc_attr( $value ),
$required_attr,
! empty( $field['pattern'] ) ? 'pattern="' . esc_attr( $field['pattern'] ) . '"' : '',
! empty( $field['maxlength'] ) ? 'maxlength="' . (int) $field['maxlength'] . '"' : ''
);
break;
case 'date':
printf(
'<input type="date" name="%1$s" id="%1$s" value="%2$s" class="input" %3$s />',
esc_attr( $key ),
esc_attr( $value ),
$required_attr
);
break;
case 'textarea':
printf(
'<textarea name="%1$s" id="%1$s" class="input" rows="3" %2$s>%3$s</textarea>',
esc_attr( $key ),
$required_attr,
esc_textarea( $value )
);
break;
case 'radio':
foreach ( $field['options'] as $opt_val => $opt_label ) {
printf(
'<label><input type="radio" name="%1$s" value="%2$s" %3$s /> %4$s</label><br/>',
esc_attr( $key ),
esc_attr( $opt_val ),
checked( $value, (string) $opt_val, false ),
esc_html( $opt_label )
);
}
break;
case 'checkbox':
printf(
'<label><input type="checkbox" name="%1$s" id="%1$s" value="1" %2$s %3$s /> %4$s</label>',
esc_attr( $key ),
checked( $value, '1', false ),
$required_attr,
'' // label is already above
);
break;
case 'file':
printf(
'<input type="file" name="%1$s" id="%1$s" accept="%2$s" />',
esc_attr( $key ),
esc_attr( $field['accept'] ?? '' )
);
if ( $value ) {
$label = $value;
if ( is_numeric( $value ) && (int) $value > 0 ) {
$p = get_post( (int) $value );
if ( $p && 'attachment' === $p->post_type ) {
$f = get_attached_file( (int) $value );
$label = $f ? wp_basename( $f ) : $p->post_title;
}
} elseif ( is_string( $value ) && ( false !== strpos( $value, '/' ) || false !== strpos( $value, '\\' ) ) ) {
$label = wp_basename( $value );
}
echo '<p class="description">' . esc_html__( 'Current file:', 'wp-ojs-sso-bridge' ) . ' ' . esc_html( $label ) . '</p>';
}
break;
}
echo '</div>';
}
public static function validate( $data, $files = [], $for_user_id = null ) {
$errors = [];
$fields = self::get_fields();
$uid = ( null !== $for_user_id ) ? (int) $for_user_id : get_current_user_id();
$required_text = [ 'ojs_birthplace', 'ojs_birthdate', 'ojs_fiscal_code', 'ojs_shipping_address', 'ojs_membership_type' ];
foreach ( $required_text as $key ) {
if ( empty( $data[ $key ] ) ) {
$errors[ $key ] = sprintf(
/* translators: %s: field label */
__( 'The field "%s" is required for subscription.', 'wp-ojs-sso-bridge' ),
$fields[ $key ]['label']
);
}
}
if ( ! empty( $data['ojs_fiscal_code'] ) && ! preg_match( '/^[A-Z0-9]{16}$/i', $data['ojs_fiscal_code'] ) ) {
$errors['ojs_fiscal_code'] = __( 'The Fiscal Code must be exactly 16 alphanumeric characters.', 'wp-ojs-sso-bridge' );
}
$type = sanitize_text_field( $data['ojs_membership_type'] ?? '' );
if ( in_array( $type, [ 'student', 'student_junior' ], true ) ) {
if ( empty( $files['ojs_student_document']['name'] ) ) {
$has = class_exists( 'WP_OJS_SSO_Subscription_Media' ) && $uid > 0
? WP_OJS_SSO_Subscription_Media::has_stored_file( $uid, WP_OJS_SSO_Subscription_Media::KIND_CERTIFICATO )
: false;
if ( ! $has ) {
$errors['ojs_student_document'] = __( 'A student certificate document is required for student memberships.', 'wp-ojs-sso-bridge' );
}
}
}
if ( empty( $files['ojs_bonifico_receipt']['name'] ?? '' ) ) {
$has_b = class_exists( 'WP_OJS_SSO_Subscription_Media' ) && $uid > 0
? WP_OJS_SSO_Subscription_Media::has_stored_file( $uid, WP_OJS_SSO_Subscription_Media::KIND_BONIFICO )
: false;
if ( ! $has_b ) {
$errors['ojs_bonifico_receipt'] = __( 'A bank transfer receipt is required for subscription requests.', 'wp-ojs-sso-bridge' );
}
}
if ( empty( $data['ojs_consent_guit_soci'] ) ) {
$errors['ojs_consent_guit_soci'] = __( 'Consent to the guit-soci mailing list is mandatory.', 'wp-ojs-sso-bridge' );
}
if ( ! isset( $data['ojs_consent_guit_members'] ) || '' === $data['ojs_consent_guit_members'] ) {
$errors['ojs_consent_guit_members'] = __( 'Please indicate your preference for the guit-members mailing list.', 'wp-ojs-sso-bridge' );
}
if ( empty( $data['ojs_consent_privacy'] ) ) {
$errors['ojs_consent_privacy'] = __( 'Consent to data processing is mandatory.', 'wp-ojs-sso-bridge' );
}
return $errors;
}
public static function save_fields( $user_id, $data ) {
$text_fields = [
'ojs_birthplace', 'ojs_birthdate', 'ojs_fiscal_code',
'ojs_shipping_address', 'ojs_membership_type',
'ojs_consent_guit_soci', 'ojs_consent_guit_members', 'ojs_consent_privacy',
];
foreach ( $text_fields as $key ) {
if ( isset( $data[ $key ] ) ) {
update_user_meta( $user_id, $key, sanitize_text_field( $data[ $key ] ) );
}
}
if ( isset( $data['first_name'] ) ) {
update_user_meta( $user_id, 'first_name', sanitize_text_field( $data['first_name'] ) );
}
if ( isset( $data['last_name'] ) ) {
update_user_meta( $user_id, 'last_name', sanitize_text_field( $data['last_name'] ) );
}
}
}