<?php
/**
* Registration form shortcode.
*
* @package TonItaliaRegistration
*/
defined( 'ABSPATH' ) || exit;
/**
* Class TON_Reg_Registration_Form
*/
class TON_Reg_Registration_Form {
/**
* Whether the registration form was rendered on the current request.
*
* @var bool
*/
private static $form_rendered = false;
/**
* Register hooks.
*/
public static function register() {
add_shortcode( 'ton_registration_form', array( __CLASS__, 'render_shortcode' ) );
add_shortcode( 'ton_registration_success', array( __CLASS__, 'render_success_shortcode' ) );
add_action( 'wp_enqueue_scripts', array( __CLASS__, 'enqueue_assets' ) );
}
/**
* Enqueue form assets when the page content includes the shortcode.
*/
public static function enqueue_assets() {
if ( self::page_has_shortcode() ) {
self::enqueue_form_assets();
}
}
/**
* Ensure assets are loaded whenever the form shortcode is actually rendered.
*/
public static function ensure_form_assets() {
self::enqueue_form_assets();
}
/**
* @return void
*/
private static function enqueue_form_assets() {
static $enqueued = false;
if ( $enqueued ) {
return;
}
$enqueued = true;
$form_css_path = TON_REG_PLUGIN_DIR . 'assets/css/form.css';
$form_js_path = TON_REG_PLUGIN_DIR . 'assets/js/form.js';
wp_enqueue_style(
'ton-reg-form',
TON_REG_PLUGIN_URL . 'assets/css/form.css',
array(),
file_exists( $form_css_path ) ? (string) filemtime( $form_css_path ) : TON_REG_VERSION
);
wp_enqueue_script(
'ton-reg-form',
TON_REG_PLUGIN_URL . 'assets/js/form.js',
array(),
file_exists( $form_js_path ) ? (string) filemtime( $form_js_path ) : TON_REG_VERSION,
true
);
wp_localize_script(
'ton-reg-form',
'tonRegForm',
array(
'msgRequired' => __( 'Compila questo campo.', 'ton-italia-registration' ),
'msgEmail' => __( 'Inserisci un indirizzo email valido.', 'ton-italia-registration' ),
'msgCf' => __( 'Codice fiscale non valido (16 caratteri).', 'ton-italia-registration' ),
'msgCap' => __( 'Il CAP deve essere di 5 cifre.', 'ton-italia-registration' ),
'msgProvincia' => __( 'Inserisci la sigla provincia (2 lettere).', 'ton-italia-registration' ),
'msgDate' => __( 'Inserisci la data nel formato gg-mm-aaaa.', 'ton-italia-registration' ),
'msgDateFuture' => __( 'La data di dichiarazione non può essere futura.', 'ton-italia-registration' ),
'msgCheckbox' => __( 'Devi selezionare questa casella per continuare.', 'ton-italia-registration' ),
'msgCaptcha' => __( 'Inserisci la risposta alla verifica anti-spam.', 'ton-italia-registration' ),
)
);
}
/**
* Mark form as rendered and attach footer fallback script.
*
* @return void
*/
private static function mark_form_rendered() {
if ( self::$form_rendered ) {
return;
}
self::$form_rendered = true;
self::ensure_form_assets();
add_action( 'wp_footer', array( __CLASS__, 'print_form_field_normalization_script' ), 20 );
}
/**
* Inline fallback so field normalization works even if external JS is blocked or cached stale.
*
* @return void
*/
public static function print_form_field_normalization_script() {
if ( ! self::$form_rendered ) {
return;
}
?>
<script id="ton-reg-form-normalize">
(function () {
function padPart(part) {
var num = parseInt(part, 10);
return part.length === 1 && num >= 1 && num <= 9 ? '0' + part : part;
}
function normalizeDate(value) {
var trimmed = (value || '').trim().replace(/[./]/g, '-').replace(/\s+/g, '-').replace(/-+/g, '-');
var match = trimmed.match(/^(\d{1,2})-(\d{1,2})-(\d{4})$/);
return match ? padPart(match[1]) + '-' + padPart(match[2]) + '-' + match[3] : trimmed;
}
function normalizeCf(value) {
return (value || '').trim().toUpperCase().replace(/\s+/g, '');
}
function normalizeProv(value) {
return (value || '').trim().toUpperCase();
}
function normalizeInput(input) {
if (!input || !input.name) {
return;
}
if ('data_nascita' === input.name || 'data_dichiarazione' === input.name) {
input.value = normalizeDate(input.value);
return;
}
if ('codice_fiscale' === input.name) {
input.value = normalizeCf(input.value);
return;
}
if ('provincia_nascita' === input.name || 'provincia_residenza' === input.name) {
input.value = normalizeProv(input.value);
}
}
function bindForm(form) {
if (!form || '1' === form.getAttribute('data-ton-reg-normalize')) {
return;
}
form.setAttribute('data-ton-reg-normalize', '1');
form.addEventListener('input', function (event) {
var input = event.target;
if (!input.classList || !input.classList.contains('ton-reg-form__input')) {
return;
}
if ('codice_fiscale' === input.name && input.value) {
input.value = normalizeCf(input.value);
}
if (('data_nascita' === input.name || 'data_dichiarazione' === input.name) && input.value) {
input.value = input.value.replace(/[./]/g, '-');
}
if (('provincia_nascita' === input.name || 'provincia_residenza' === input.name) && input.value) {
input.value = normalizeProv(input.value);
}
});
form.addEventListener('focusout', function (event) {
var input = event.target;
if (!input.classList || !input.classList.contains('ton-reg-form__input')) {
return;
}
normalizeInput(input);
}, true);
}
function init() {
document.querySelectorAll('.ton-reg-form__body').forEach(bindForm);
if (typeof window.tonRegFormInit === 'function') {
window.tonRegFormInit();
}
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();
</script>
<?php
}
/**
* @return bool
*/
private static function page_has_shortcode() {
global $post;
if ( $post instanceof WP_Post ) {
if ( self::content_has_shortcode( $post->post_content, 'ton_registration_form' ) ) {
return true;
}
if ( self::content_has_shortcode( $post->post_content, 'ton_registration_success' ) ) {
return true;
}
}
return isset( $_GET['ton_reg'] ) && in_array( $_GET['ton_reg'], array( 'success', 'error' ), true );
}
/**
* @param string $content Post content.
* @param string $tag Shortcode tag.
* @return bool
*/
private static function content_has_shortcode( $content, $tag ) {
if ( ! is_string( $content ) || '' === $content ) {
return false;
}
if ( has_shortcode( $content, $tag ) ) {
return true;
}
if ( false !== strpos( $content, '[' . $tag ) ) {
return true;
}
if ( function_exists( 'parse_blocks' ) && false !== strpos( $content, '<!-- wp:' ) ) {
return self::blocks_contain_shortcode( parse_blocks( $content ), $tag );
}
return false;
}
/**
* @param array<int,array<string,mixed>> $blocks Parsed blocks.
* @param string $tag Shortcode tag.
* @return bool
*/
private static function blocks_contain_shortcode( $blocks, $tag ) {
foreach ( $blocks as $block ) {
$block_name = $block['blockName'] ?? '';
$inner_html = $block['innerHTML'] ?? '';
if ( 'core/shortcode' === $block_name && false !== strpos( $inner_html, '[' . $tag ) ) {
return true;
}
if ( is_string( $inner_html ) && has_shortcode( $inner_html, $tag ) ) {
return true;
}
if ( ! empty( $block['innerBlocks'] ) && self::blocks_contain_shortcode( $block['innerBlocks'], $tag ) ) {
return true;
}
}
return false;
}
/**
* HTML shown after a successful registration.
*
* @return string
*/
public static function get_success_message_html() {
$message = get_option( 'ton_reg_success_message', false );
if ( false === $message || '' === trim( wp_strip_all_tags( (string) $message ) ) ) {
$defaults = TON_Reg_Defaults::options();
$message = $defaults['ton_reg_success_message'];
}
return (string) $message;
}
/**
* @param array<string,string> $atts Attributes.
* @return string
*/
public static function render_shortcode( $atts ) {
self::ensure_form_assets();
$atts = shortcode_atts(
array( 'class' => '' ),
$atts,
'ton_registration_form'
);
// Fallback: messaggio sulla stessa pagina del form se non è configurata una pagina di conferma.
if (
! (int) get_option( 'ton_reg_success_page_id', 0 )
&& isset( $_GET['ton_reg'] )
&& 'success' === $_GET['ton_reg']
) {
return self::render_success_message( $atts['class'] );
}
$token = TON_Reg_Captcha::create_token();
$challenge = TON_Reg_Captcha::generate_challenge( $token );
ob_start();
self::render_form( $atts['class'], $token, $challenge );
return ob_get_clean();
}
/**
* @param array<string,string> $atts Attributes.
* @return string
*/
public static function render_success_shortcode( $atts ) {
$atts = shortcode_atts(
array( 'class' => '' ),
$atts,
'ton_registration_success'
);
if ( ! isset( $_GET['ton_reg'] ) || 'success' !== $_GET['ton_reg'] ) {
return '';
}
return self::render_success_message( $atts['class'] );
}
/**
* @param string $extra_class Optional CSS class.
* @return string
*/
public static function render_success_message( $extra_class = '' ) {
$html = self::get_success_message_html();
$class = 'ton-reg-form ton-reg-form--success' . ( $extra_class ? ' ' . esc_attr( $extra_class ) : '' );
return '<div class="' . esc_attr( trim( $class ) ) . '" id="ton-reg-success" role="status" aria-live="polite">' . wp_kses_post( $html ) . '</div>';
}
/**
* @param string $type success|error.
* @return string
*/
private static function render_message( $type ) {
if ( 'success' === $type ) {
return self::render_success_message();
}
$msg = isset( $_GET['ton_msg'] ) ? sanitize_text_field( wp_unslash( rawurldecode( $_GET['ton_msg'] ) ) ) : '';
return '<div class="ton-reg-form__alert ton-reg-form__alert--error" role="alert"><p>' . esc_html( $msg ) . '</p></div>';
}
/**
* @param string $extra_class Extra CSS class.
* @param string $token Form token.
* @param array<string,mixed> $challenge Captcha challenge.
*/
private static function render_form( $extra_class, $token, $challenge ) {
self::mark_form_rendered();
$payment = self::replace_payment_placeholders( get_option( 'ton_reg_payment_instructions', '' ) );
$wrapper_class = 'ton-reg-form' . ( $extra_class ? ' ' . esc_attr( $extra_class ) : '' );
?>
<div class="<?php echo esc_attr( $wrapper_class ); ?>">
<?php if ( isset( $_GET['ton_reg'] ) && 'error' === $_GET['ton_reg'] ) : ?>
<?php echo self::render_message( 'error' ); ?>
<?php endif; ?>
<form class="ton-reg-form__body" method="post" action="<?php echo esc_url( TON_Reg_Registration_Handler::get_form_page_action_url() ); ?>">
<input type="hidden" name="ton_reg_frontend" value="1" />
<?php
$form_page_id = TON_Reg_Registration_Handler::get_form_page_id();
if ( $form_page_id ) :
?>
<input type="hidden" name="ton_reg_page_id" value="<?php echo (int) $form_page_id; ?>" />
<input type="hidden" name="ton_reg_redirect" value="<?php echo esc_url( get_permalink( $form_page_id ) ); ?>" />
<?php endif; ?>
<?php wp_nonce_field( TON_Reg_Captcha::NONCE_ACTION, 'ton_reg_nonce' ); ?>
<input type="hidden" name="<?php echo esc_attr( TON_Reg_Captcha::FIELD_TOKEN ); ?>" value="<?php echo esc_attr( $token ); ?>" />
<p class="ton-reg-form__intro"><?php esc_html_e( 'Domanda di ammissione a socio e contestuale tesseramento', 'ton-italia-registration' ); ?></p>
<fieldset class="ton-reg-form__fieldset ton-reg-form__payment">
<legend><?php esc_html_e( 'Quota associativa', 'ton-italia-registration' ); ?></legend>
<div class="ton-reg-form__richtext"><?php echo wp_kses_post( $payment ); ?></div>
<label class="ton-reg-form__checkbox">
<input type="checkbox" name="bonifico_effettuato" value="1" />
<span><?php esc_html_e( 'Ho effettuato il bonifico (o provvederò a breve)', 'ton-italia-registration' ); ?></span>
</label>
</fieldset>
<fieldset class="ton-reg-form__fieldset">
<legend><?php esc_html_e( 'Dati anagrafici', 'ton-italia-registration' ); ?></legend>
<div class="ton-reg-form__grid">
<?php self::field_text( 'cognome', __( 'Cognome', 'ton-italia-registration' ), true ); ?>
<?php self::field_text( 'nome', __( 'Nome', 'ton-italia-registration' ), true ); ?>
<?php self::field_text( 'luogo_nascita', __( 'Nato/a a', 'ton-italia-registration' ), true ); ?>
<?php self::field_text( 'provincia_nascita', __( 'Prov.', 'ton-italia-registration' ), true, '2', 'text', '', '[A-Za-z]{2}' ); ?>
<?php self::field_text( 'data_nascita', __( 'Data di nascita', 'ton-italia-registration' ), true, '10', 'text', '', '[0-9]{1,2}[-/.][0-9]{1,2}[-/.][0-9]{4}' ); ?>
<?php self::field_text( 'codice_fiscale', __( 'Codice fiscale', 'ton-italia-registration' ), true, '16', 'text', '', '[A-Za-z]{6}[0-9]{2}[A-Za-z][0-9]{2}[A-Za-z][0-9]{3}[A-Za-z]' ); ?>
<?php self::field_text( 'comune_residenza', __( 'Residente in', 'ton-italia-registration' ), true ); ?>
<?php self::field_text( 'provincia_residenza', __( 'Prov.', 'ton-italia-registration' ), true, '2', 'text', '', '[A-Za-z]{2}' ); ?>
<?php self::field_text( 'indirizzo', __( 'Via/Piazza', 'ton-italia-registration' ), true ); ?>
<?php self::field_text( 'numero_civico', __( 'n.', 'ton-italia-registration' ), true, '10' ); ?>
<?php self::field_text( 'cap', __( 'CAP', 'ton-italia-registration' ), true, '5', 'text', '', '[0-9]{5}' ); ?>
<?php self::field_text( 'telefono', __( 'Telefono / Cellulare', 'ton-italia-registration' ), true, '', 'tel' ); ?>
<?php self::field_text( 'email', __( 'Email', 'ton-italia-registration' ), true, '', 'email' ); ?>
</div>
</fieldset>
<fieldset class="ton-reg-form__fieldset">
<legend><?php esc_html_e( 'Dichiarazione', 'ton-italia-registration' ); ?></legend>
<p class="ton-reg-form__declaration"><?php echo esc_html( get_option( 'ton_reg_statuto_declaration', '' ) ); ?></p>
<div class="ton-reg-form__grid ton-reg-form__grid--narrow">
<?php self::field_text( 'luogo_dichiarazione', __( 'Luogo', 'ton-italia-registration' ), true ); ?>
<?php self::field_text( 'data_dichiarazione', __( 'Data', 'ton-italia-registration' ), true, '10', 'text', '', '[0-9]{1,2}[-/.][0-9]{1,2}[-/.][0-9]{4}' ); ?>
</div>
<label class="ton-reg-form__checkbox ton-reg-form__checkbox--required">
<input type="checkbox" name="accettazione_statuto" value="1" required />
<span><?php esc_html_e( 'Dichiaro di aver letto e accettato quanto sopra (sostitutivo della firma).', 'ton-italia-registration' ); ?></span>
</label>
<p class="ton-reg-form__minor"><?php echo esc_html( get_option( 'ton_reg_minor_notice', '' ) ); ?></p>
</fieldset>
<fieldset class="ton-reg-form__fieldset">
<legend><?php esc_html_e( 'Privacy', 'ton-italia-registration' ); ?></legend>
<div class="ton-reg-form__richtext"><?php echo wp_kses_post( get_option( 'ton_reg_privacy_notice', '' ) ); ?></div>
<label class="ton-reg-form__checkbox ton-reg-form__checkbox--required">
<input type="checkbox" name="consenso_privacy" value="1" required />
<span><?php esc_html_e( 'Acconsento al trattamento dei dati personali come da informativa (sostitutivo della firma per consenso).', 'ton-italia-registration' ); ?></span>
</label>
<label class="ton-reg-form__checkbox<?php echo '1' === get_option( 'ton_reg_newsletter_required', '0' ) ? ' ton-reg-form__checkbox--required' : ''; ?>">
<input type="checkbox" name="consenso_newsletter" value="1" <?php echo '1' === get_option( 'ton_reg_newsletter_required', '0' ) ? 'required' : ''; ?> />
<span><?php echo esc_html( get_option( 'ton_reg_newsletter_label', '' ) ); ?></span>
</label>
</fieldset>
<?php if ( TON_Reg_Captcha::is_enabled() ) : ?>
<fieldset class="ton-reg-form__fieldset ton-reg-form__captcha">
<legend><?php esc_html_e( 'Verifica anti-spam', 'ton-italia-registration' ); ?></legend>
<label class="ton-reg-form__honeypot" aria-hidden="true">
<?php esc_html_e( 'Lascia vuoto questo campo', 'ton-italia-registration' ); ?>
<input type="text" name="<?php echo esc_attr( TON_Reg_Captcha::FIELD_HONEYPOT ); ?>" value="" tabindex="-1" autocomplete="off" />
</label>
<p class="ton-reg-form__field">
<label for="ton_reg_captcha_answer"><?php echo esc_html( $challenge['question'] ); ?> <span class="required">*</span></label>
<input type="number" id="ton_reg_captcha_answer" class="ton-reg-form__input" name="<?php echo esc_attr( TON_Reg_Captcha::FIELD_MATH ); ?>" required inputmode="numeric" placeholder="<?php esc_attr_e( 'Inserisci il risultato', 'ton-italia-registration' ); ?>" />
</p>
</fieldset>
<?php endif; ?>
<p class="ton-reg-form__submit">
<button type="submit" class="ton-reg-form__button"><?php esc_html_e( 'Invia domanda di iscrizione', 'ton-italia-registration' ); ?></button>
</p>
</form>
</div>
<?php
}
/**
* @param string $name Field name.
* @param string $label Label.
* @param bool $required Required.
* @param string $maxlength Max length.
* @param string $type Input type.
* @param string $placeholder Placeholder override.
* @param string $pattern HTML pattern.
*/
private static function field_text( $name, $label, $required = false, $maxlength = '', $type = 'text', $placeholder = '', $pattern = '' ) {
$id = 'ton_reg_' . $name;
$holders = self::placeholders();
$placeholder = '' !== $placeholder ? $placeholder : ( $holders[ $name ] ?? '' );
?>
<p class="ton-reg-form__field" data-field="<?php echo esc_attr( $name ); ?>">
<label for="<?php echo esc_attr( $id ); ?>"><?php echo esc_html( $label ); ?><?php if ( $required ) : ?> <span class="required">*</span><?php endif; ?></label>
<input
class="ton-reg-form__input"
type="<?php echo esc_attr( $type ); ?>"
id="<?php echo esc_attr( $id ); ?>"
name="<?php echo esc_attr( $name ); ?>"
value="<?php echo esc_attr( self::old( $name ) ); ?>"
<?php echo $required ? 'required' : ''; ?>
<?php echo $maxlength ? 'maxlength="' . esc_attr( $maxlength ) . '"' : ''; ?>
<?php echo $placeholder ? 'placeholder="' . esc_attr( $placeholder ) . '"' : ''; ?>
<?php echo $pattern ? 'pattern="' . esc_attr( $pattern ) . '"' : ''; ?>
<?php echo 'email' === $type ? 'autocomplete="email"' : ''; ?>
/>
<span class="ton-reg-form__error" role="alert" hidden></span>
</p>
<?php
}
/**
* @return array<string, string>
*/
private static function placeholders() {
return array(
'cognome' => __( 'Inserisci il cognome', 'ton-italia-registration' ),
'nome' => __( 'Inserisci il nome', 'ton-italia-registration' ),
'luogo_nascita' => __( 'Comune o stato di nascita', 'ton-italia-registration' ),
'provincia_nascita' => __( 'Sigla provincia, es. VR', 'ton-italia-registration' ),
'data_nascita' => __( 'gg-mm-aaaa', 'ton-italia-registration' ),
'codice_fiscale' => __( '16 caratteri alfanumerici', 'ton-italia-registration' ),
'comune_residenza' => __( 'Comune di residenza', 'ton-italia-registration' ),
'provincia_residenza' => __( 'Sigla provincia, es. MI', 'ton-italia-registration' ),
'indirizzo' => __( 'Via o piazza', 'ton-italia-registration' ),
'numero_civico' => __( 'Numero civico', 'ton-italia-registration' ),
'cap' => __( '5 cifre', 'ton-italia-registration' ),
'telefono' => __( 'Telefono o cellulare', 'ton-italia-registration' ),
'email' => __( 'nome@esempio.it', 'ton-italia-registration' ),
'luogo_dichiarazione' => __( 'Comune della dichiarazione', 'ton-italia-registration' ),
'data_dichiarazione' => __( 'gg-mm-aaaa', 'ton-italia-registration' ),
);
}
/**
* @param string $key Field key.
* @return string
*/
private static function old( $key ) {
// No session storage for security; empty on fresh load.
return '';
}
/**
* @param string $html HTML template.
* @return string
*/
private static function replace_payment_placeholders( $html ) {
return strtr(
$html,
array(
'{quota}' => esc_html( get_option( 'ton_reg_membership_fee', '10,00' ) ),
'{anno}' => esc_html( get_option( 'ton_reg_social_year', '2026' ) ),
'{beneficiario}' => esc_html( get_option( 'ton_reg_beneficiary', '' ) ),
'{iban}' => esc_html( get_option( 'ton_reg_iban', '' ) ),
'{nome}' => '',
'{cognome}' => '',
)
);
}
}