diff --git a/README.md b/README.md index 6da2870..6527d43 100644 --- a/README.md +++ b/README.md @@ -18,9 +18,15 @@ - GitBucket: `https://niphredil.duckdns.org/git/fabio/tonitalia-pluginsoci.git` +## Mailchimp (v1.6+) + +In **TON Iscrizioni → Impostazioni → Integrazione Mailchimp** configura API key e List ID. +I richiedenti che accettano la newsletter nel form vengono iscritti automaticamente alla lista configurata. + ## Documentazione -Vedi `readme.txt` per changelog e note GDPR (formato WordPress.org). +Vedi `readme.txt` per changelog e note GDPR (formato WordPress.org). +Vedi `deploy/wiki-tonitalia-pluginsoci.md` per la guida operativa completa. ## Versione diff --git a/admin/class-admin.php b/admin/class-admin.php index d97a111..df2bfd4 100644 --- a/admin/class-admin.php +++ b/admin/class-admin.php @@ -25,6 +25,8 @@ add_action( 'admin_post_ton_reg_gdpr_erase', array( __CLASS__, 'gdpr_erase' ) ); add_action( 'admin_post_ton_reg_upload_document', array( __CLASS__, 'upload_document' ) ); add_action( 'admin_post_ton_reg_delete_document', array( __CLASS__, 'delete_document' ) ); + add_action( 'admin_post_ton_reg_mailchimp_test', array( __CLASS__, 'mailchimp_test' ) ); + add_action( 'admin_post_ton_reg_mailchimp_retry', array( __CLASS__, 'mailchimp_retry' ) ); } /** @@ -88,6 +90,7 @@ 'ton_reg_captcha_enabled', 'ton_reg_newsletter_required', 'ton_reg_delete_users_on_uninstall', + 'ton_reg_mailchimp_enabled', ); $plain_text = array( @@ -102,10 +105,42 @@ 'ton_reg_rate_limit_max', 'ton_reg_rate_limit_window', 'ton_reg_privacy_version', + 'ton_reg_mailchimp_tags', + ); + + $skip_auto = array( + 'ton_reg_mailchimp_api_key', + 'ton_reg_mailchimp_list_id', + 'ton_reg_mailchimp_permission_ids', + ); + + register_setting( + 'ton_reg_settings', + 'ton_reg_mailchimp_api_key', + array( + 'type' => 'string', + 'sanitize_callback' => array( 'TON_Reg_Mailchimp', 'sanitize_api_key' ), + 'show_in_rest' => false, + 'default' => '', + ) + ); + + register_setting( + 'ton_reg_settings', + 'ton_reg_mailchimp_list_id', + array( + 'type' => 'string', + 'sanitize_callback' => array( 'TON_Reg_Mailchimp', 'sanitize_list_id' ), + 'show_in_rest' => false, + 'default' => '', + ) ); $options = array_keys( TON_Reg_Defaults::options() ); foreach ( $options as $option ) { + if ( in_array( $option, $skip_auto, true ) ) { + continue; + } if ( in_array( $option, $checkboxes, true ) ) { $sanitize = array( __CLASS__, 'sanitize_checkbox' ); } elseif ( in_array( $option, $plain_text, true ) ) { @@ -318,6 +353,7 @@ consenso_newsletter ) ) : ?> + @@ -365,6 +401,46 @@ } /** + * @param object $row Registration row. + */ + private static function render_mailchimp_sync_status( $row ) { + $status = isset( $row->mailchimp_status ) ? (string) $row->mailchimp_status : ''; + + if ( '' === $status ) { + if ( TON_Reg_Mailchimp::is_configured() ) { + echo '

' . esc_html__( 'Mailchimp: in attesa di sincronizzazione.', 'ton-italia-registration' ) . '

'; + } + return; + } + + $labels = array( + 'pending' => __( 'Mailchimp: sincronizzazione in corso', 'ton-italia-registration' ), + 'synced' => __( 'Mailchimp: iscritto correttamente', 'ton-italia-registration' ), + 'error' => __( 'Mailchimp: errore di sincronizzazione', 'ton-italia-registration' ), + 'skipped' => __( 'Mailchimp: non sincronizzato (integrazione disattiva)', 'ton-italia-registration' ), + ); + + $label = $labels[ $status ] ?? $status; + echo '

' . esc_html( $label ) . '

'; + + if ( ! empty( $row->mailchimp_synced_at ) && 'synced' === $status ) { + echo '

' . esc_html( self::format_consent_datetime( $row->mailchimp_synced_at ) ) . '

'; + } + + if ( ! empty( $row->mailchimp_error ) && 'error' === $status ) { + echo '

' . esc_html( $row->mailchimp_error ) . '

'; + } + + if ( TON_Reg_Mailchimp::is_configured() && in_array( $status, array( 'error', 'pending' ), true ) ) { + $retry_url = wp_nonce_url( + admin_url( 'admin-post.php?action=ton_reg_mailchimp_retry&id=' . (int) $row->id ), + 'ton_reg_mc_retry_' . (int) $row->id + ); + echo '

' . esc_html__( 'Riprova iscrizione Mailchimp', 'ton-italia-registration' ) . '

'; + } + } + + /** * @param string $datetime UTC datetime from DB. * @return string */ @@ -403,6 +479,13 @@ $msg = sanitize_text_field( wp_unslash( rawurldecode( $_GET['doc_error'] ) ) ); echo '

' . esc_html( $msg ) . '

'; } + if ( isset( $_GET['mc_ok'] ) ) { + echo '

' . esc_html__( 'Sincronizzazione Mailchimp completata.', 'ton-italia-registration' ) . '

'; + } + if ( ! empty( $_GET['mc_error'] ) ) { + $msg = sanitize_text_field( wp_unslash( rawurldecode( $_GET['mc_error'] ) ) ); + echo '

' . esc_html( $msg ) . '

'; + } } /** @@ -504,6 +587,13 @@

+ +

+ + +

+ +

@@ -540,6 +630,39 @@ /> /> /> + + +

+

+ + + + + + + + + + + + + + + + + +
/>
+ +

+
+ +

+
+ +

+
+ + $label ) : ?> @@ -554,6 +677,28 @@

+ + + + +

+

+
+ + + + + + + + +
+ +
+ +
+ +
get_error_message() ), + $redirect + ) + ); + exit; + } + + wp_safe_redirect( add_query_arg( 'mc_test_ok', '1', $redirect ) ); + exit; + } + + /** + * Retry Mailchimp sync for a single registration. + */ + public static function mailchimp_retry() { + $id = isset( $_GET['id'] ) ? (int) $_GET['id'] : 0; + + if ( ! current_user_can( 'manage_options' ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ?? '' ) ), 'ton_reg_mc_retry_' . $id ) ) { + wp_die( esc_html__( 'Non autorizzato.', 'ton-italia-registration' ) ); + } + + $row = TON_Reg_Database::get( $id ); + if ( ! $row || empty( $row->consenso_newsletter ) ) { + wp_safe_redirect( + add_query_arg( + 'mc_error', + rawurlencode( __( 'Consenso newsletter assente.', 'ton-italia-registration' ) ), + admin_url( 'admin.php?page=ton-registrations&action=view&id=' . $id ) + ) + ); + exit; + } + + if ( ! TON_Reg_Mailchimp::is_configured() ) { + wp_safe_redirect( + add_query_arg( + 'mc_error', + rawurlencode( __( 'Integrazione Mailchimp non configurata.', 'ton-italia-registration' ) ), + admin_url( 'admin.php?page=ton-registrations&action=view&id=' . $id ) + ) + ); + exit; + } + + $ok = TON_Reg_Mailchimp::sync_registration( $id ); + $redirect = admin_url( 'admin.php?page=ton-registrations&action=view&id=' . $id ); + + if ( $ok ) { + wp_safe_redirect( add_query_arg( 'mc_ok', '1', $redirect ) ); + exit; + } + + $row = TON_Reg_Database::get( $id ); + $error = ! empty( $row->mailchimp_error ) ? $row->mailchimp_error : __( 'Sincronizzazione Mailchimp non riuscita.', 'ton-italia-registration' ); + + wp_safe_redirect( + add_query_arg( + 'mc_error', + rawurlencode( $error ), + $redirect + ) + ); + exit; + } } diff --git a/includes/class-autoloader.php b/includes/class-autoloader.php index 399fca4..54c20fb 100644 --- a/includes/class-autoloader.php +++ b/includes/class-autoloader.php @@ -37,6 +37,7 @@ 'TON_Reg_Captcha' => 'includes/class-captcha.php', 'TON_Reg_User_Manager' => 'includes/class-user-manager.php', 'TON_Reg_Mailer' => 'includes/class-mailer.php', + 'TON_Reg_Mailchimp' => 'includes/class-mailchimp.php', 'TON_Reg_Gdpr' => 'includes/class-gdpr.php', 'TON_Reg_Documents' => 'includes/class-documents.php', 'TON_Reg_Registration_Form' => 'includes/class-registration-form.php', diff --git a/includes/class-database.php b/includes/class-database.php index afa900e..eef39a1 100644 --- a/includes/class-database.php +++ b/includes/class-database.php @@ -63,6 +63,9 @@ doc_bonifico_id bigint(20) unsigned DEFAULT NULL, doc_pagamento_id bigint(20) unsigned DEFAULT NULL, gdpr_log longtext NULL, + mailchimp_status varchar(20) DEFAULT NULL, + mailchimp_synced_at datetime DEFAULT NULL, + mailchimp_error varchar(255) DEFAULT NULL, created_at datetime NOT NULL, updated_at datetime NOT NULL, anonymized_at datetime DEFAULT NULL, diff --git a/includes/class-defaults.php b/includes/class-defaults.php index 045d3c6..e23693a 100644 --- a/includes/class-defaults.php +++ b/includes/class-defaults.php @@ -39,6 +39,11 @@ 'ton_reg_newsletter_required' => '0', 'ton_reg_privacy_version' => '1', 'ton_reg_delete_users_on_uninstall' => '0', + 'ton_reg_mailchimp_enabled' => '0', + 'ton_reg_mailchimp_api_key' => '', + 'ton_reg_mailchimp_list_id' => '', + 'ton_reg_mailchimp_tags' => 'Socio TON ITALIA', + 'ton_reg_mailchimp_permission_ids' => '[]', ); } diff --git a/includes/class-mailchimp.php b/includes/class-mailchimp.php new file mode 100644 index 0000000..54736dc --- /dev/null +++ b/includes/class-mailchimp.php @@ -0,0 +1,505 @@ + 'pending', + 'mailchimp_error' => null, + ) + ); + + wp_schedule_single_event( time(), self::CRON_HOOK, array( $registration_id ) ); + } + + /** + * @param int $registration_id Registration ID. + * @return bool True on success. + */ + public static function sync_registration( $registration_id ) { + $registration_id = (int) $registration_id; + $row = TON_Reg_Database::get( $registration_id ); + + if ( ! $row ) { + return false; + } + + if ( empty( $row->consenso_newsletter ) ) { + self::record_status( $registration_id, 'skipped', '' ); + return true; + } + + if ( ! self::is_configured() ) { + self::record_status( $registration_id, 'skipped', '' ); + return true; + } + + $email = sanitize_email( $row->email ); + if ( ! is_email( $email ) ) { + self::record_status( $registration_id, 'error', __( 'Email non valida per Mailchimp.', 'ton-italia-registration' ) ); + return false; + } + + $subscriber_hash = self::subscriber_hash( $email ); + $list_id = self::get_list_id(); + $merge_fields = array( + 'FNAME' => self::truncate_merge_field( $row->nome ?? '' ), + 'LNAME' => self::truncate_merge_field( $row->cognome ?? '' ), + ); + + $body = array( + 'email_address' => $email, + 'status_if_new' => 'subscribed', + 'merge_fields' => $merge_fields, + ); + + $permissions = self::get_marketing_permissions_payload(); + if ( ! empty( $permissions ) ) { + $body['marketing_permissions'] = $permissions; + } + + $put = self::api_request( + 'PUT', + '/lists/' . $list_id . '/members/' . $subscriber_hash, + $body + ); + + if ( is_wp_error( $put ) ) { + self::record_status( $registration_id, 'error', $put->get_error_message() ); + self::debug_log( 'Mailchimp PUT failed for registration ' . $registration_id ); + return false; + } + + $member_status = isset( $put['status'] ) ? (string) $put['status'] : ''; + + if ( 'cleaned' === $member_status ) { + self::record_status( + $registration_id, + 'error', + __( 'Contatto in stato cleaned in Mailchimp — gestione manuale richiesta.', 'ton-italia-registration' ) + ); + return false; + } + + if ( 'unsubscribed' === $member_status ) { + $patch_body = array( 'status' => 'subscribed' ); + if ( ! empty( $permissions ) ) { + $patch_body['marketing_permissions'] = $permissions; + } + + $patch = self::api_request( + 'PATCH', + '/lists/' . $list_id . '/members/' . $subscriber_hash, + $patch_body + ); + + if ( is_wp_error( $patch ) ) { + self::record_status( $registration_id, 'error', $patch->get_error_message() ); + self::debug_log( 'Mailchimp PATCH failed for registration ' . $registration_id ); + return false; + } + + $member_status = isset( $patch['status'] ) ? (string) $patch['status'] : $member_status; + } + + $tags = self::parse_tags(); + if ( ! empty( $tags ) ) { + $tag_result = self::api_request( + 'POST', + '/lists/' . $list_id . '/members/' . $subscriber_hash . '/tags', + array( + 'tags' => array_map( + static function ( $name ) { + return array( + 'name' => $name, + 'status' => 'active', + ); + }, + $tags + ), + ) + ); + + if ( is_wp_error( $tag_result ) ) { + self::record_status( $registration_id, 'error', $tag_result->get_error_message() ); + self::debug_log( 'Mailchimp tags failed for registration ' . $registration_id ); + return false; + } + } + + if ( 'subscribed' !== $member_status && 'pending' !== $member_status ) { + self::record_status( + $registration_id, + 'error', + sprintf( + /* translators: %s: Mailchimp member status */ + __( 'Stato Mailchimp inatteso: %s', 'ton-italia-registration' ), + $member_status + ) + ); + return false; + } + + self::record_status( $registration_id, 'synced', '' ); + return true; + } + + /** + * Test API credentials and list access; cache marketing permission IDs. + * + * @param string $api_key_override Optional API key from unsaved form. + * @param string $list_id_override Optional list ID from unsaved form. + * @return true|WP_Error + */ + public static function test_connection( $api_key_override = '', $list_id_override = '' ) { + $api_key = '' !== (string) $api_key_override ? (string) $api_key_override : self::get_api_key(); + $list_id = '' !== (string) $list_id_override ? (string) $list_id_override : (string) get_option( 'ton_reg_mailchimp_list_id', '' ); + + if ( '' !== (string) $api_key_override && ! preg_match( '/^.+-[a-z]{2}\d+$/i', (string) $api_key_override ) ) { + return new WP_Error( 'mailchimp', __( 'Formato API key Mailchimp non valido (atteso: chiave-us12).', 'ton-italia-registration' ) ); + } + + if ( '' !== (string) $api_key && ! preg_match( '/^.+-[a-z]{2}\d+$/i', (string) $api_key ) ) { + return new WP_Error( 'mailchimp', __( 'Formato API key Mailchimp non valido (atteso: chiave-us12).', 'ton-italia-registration' ) ); + } + + if ( '' === $api_key ) { + return new WP_Error( 'mailchimp', __( 'API key Mailchimp non configurata.', 'ton-italia-registration' ) ); + } + + if ( ! self::is_valid_list_id( $list_id ) ) { + return new WP_Error( 'mailchimp', __( 'List ID Mailchimp non valido.', 'ton-italia-registration' ) ); + } + + $ping = self::api_request_with_key( 'GET', '/ping', null, $api_key ); + if ( is_wp_error( $ping ) ) { + return $ping; + } + + $list = self::api_request_with_key( 'GET', '/lists/' . $list_id, null, $api_key ); + if ( is_wp_error( $list ) ) { + return $list; + } + + $permission_ids = self::extract_permission_ids_from_list( $list ); + update_option( 'ton_reg_mailchimp_permission_ids', wp_json_encode( $permission_ids ), false ); + + return true; + } + + /** + * Keep API key out of autoloaded options snapshot. + */ + public static function ensure_api_key_no_autoload() { + global $wpdb; + + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching + $wpdb->update( + $wpdb->options, + array( 'autoload' => 'no' ), + array( 'option_name' => 'ton_reg_mailchimp_api_key' ), + array( '%s' ), + array( '%s' ) + ); + } + + /** + * @param string $email Email. + * @return string + */ + public static function subscriber_hash( $email ) { + return md5( strtolower( trim( (string) $email ) ) ); + } + + /** + * @param string $value Merge field value. + * @return string + */ + private static function truncate_merge_field( $value ) { + $value = sanitize_text_field( (string) $value ); + if ( function_exists( 'mb_substr' ) ) { + return mb_substr( $value, 0, 100 ); + } + return substr( $value, 0, 100 ); + } + + /** + * @return array> + */ + private static function get_marketing_permissions_payload() { + $raw = (string) get_option( 'ton_reg_mailchimp_permission_ids', '[]' ); + $ids = json_decode( $raw, true ); + if ( ! is_array( $ids ) || empty( $ids ) ) { + return array(); + } + + $payload = array(); + foreach ( $ids as $id ) { + $id = sanitize_text_field( (string) $id ); + if ( '' !== $id ) { + $payload[] = array( + 'marketing_permission_id' => $id, + 'enabled' => true, + ); + } + } + + return $payload; + } + + /** + * @return array + */ + private static function parse_tags() { + $raw = (string) get_option( 'ton_reg_mailchimp_tags', 'Socio TON ITALIA' ); + $tags = array_map( 'trim', explode( ',', $raw ) ); + $tags = array_filter( + array_map( 'sanitize_text_field', $tags ), + static function ( $tag ) { + return '' !== $tag; + } + ); + + return array_slice( array_values( $tags ), 0, 5 ); + } + + /** + * @param array $list List API response. + * @return array + */ + private static function extract_permission_ids_from_list( $list ) { + $ids = array(); + + if ( ! empty( $list['marketing_permissions'] ) && is_array( $list['marketing_permissions'] ) ) { + foreach ( $list['marketing_permissions'] as $permission ) { + if ( ! empty( $permission['marketing_permission_id'] ) ) { + $ids[] = sanitize_text_field( (string) $permission['marketing_permission_id'] ); + } + } + } + + return array_values( array_unique( $ids ) ); + } + + /** + * @param string $method HTTP method. + * @param string $path API path starting with /. + * @param array|null $body Request body. + * @return array|WP_Error + */ + private static function api_request( $method, $path, $body = null ) { + return self::api_request_with_key( $method, $path, $body, self::get_api_key() ); + } + + /** + * @param string $method HTTP method. + * @param string $path API path starting with /. + * @param array|null $body Request body. + * @param string $api_key API key. + * @return array|WP_Error + */ + private static function api_request_with_key( $method, $path, $body, $api_key ) { + $dc = self::extract_datacenter( $api_key ); + + if ( ! $dc ) { + return new WP_Error( 'mailchimp', __( 'API key Mailchimp non valida.', 'ton-italia-registration' ) ); + } + + $url = 'https://' . $dc . '.api.mailchimp.com/3.0' . $path; + $args = array( + 'method' => strtoupper( $method ), + 'timeout' => 10, + 'headers' => array( + 'Authorization' => 'Basic ' . base64_encode( 'ton_reg:' . $api_key ), + 'Content-Type' => 'application/json', + ), + ); + + if ( null !== $body ) { + $args['body'] = wp_json_encode( $body ); + } + + $response = wp_remote_request( $url, $args ); + if ( is_wp_error( $response ) ) { + return new WP_Error( 'mailchimp', __( 'Impossibile contattare Mailchimp.', 'ton-italia-registration' ) ); + } + + $code = (int) wp_remote_retrieve_response_code( $response ); + $raw = wp_remote_retrieve_body( $response ); + $data = json_decode( $raw, true ); + + if ( $code < 200 || $code >= 300 ) { + return new WP_Error( 'mailchimp', self::parse_api_error( $data, $code ) ); + } + + return is_array( $data ) ? $data : array(); + } + + /** + * @param mixed $data Response JSON. + * @param int $code HTTP code. + * @return string + */ + private static function parse_api_error( $data, $code ) { + $message = sprintf( + /* translators: %d: HTTP status code */ + __( 'Errore Mailchimp (HTTP %d).', 'ton-italia-registration' ), + $code + ); + + if ( is_array( $data ) ) { + if ( ! empty( $data['detail'] ) && is_string( $data['detail'] ) ) { + $message = sanitize_text_field( $data['detail'] ); + } elseif ( ! empty( $data['title'] ) && is_string( $data['title'] ) ) { + $message = sanitize_text_field( $data['title'] ); + } + } + + if ( function_exists( 'mb_substr' ) ) { + return mb_substr( $message, 0, 255 ); + } + + return substr( $message, 0, 255 ); + } + + /** + * @param string $api_key API key. + * @return string Empty if invalid. + */ + private static function extract_datacenter( $api_key ) { + if ( ! preg_match( '/-([a-z]{2}\d+)$/', (string) $api_key, $matches ) ) { + return ''; + } + return $matches[1]; + } + + /** + * @param int $registration_id Registration ID. + * @param string $status Status slug. + * @param string $error Error message. + */ + private static function record_status( $registration_id, $status, $error ) { + $data = array( + 'mailchimp_status' => sanitize_text_field( $status ), + 'mailchimp_error' => '' !== $error ? sanitize_text_field( $error ) : null, + ); + + if ( 'synced' === $status ) { + $data['mailchimp_synced_at'] = current_time( 'mysql', true ); + } + + TON_Reg_Database::update( $registration_id, $data ); + } + + /** + * @param string $message Log message without PII. + */ + private static function debug_log( $message ) { + if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { + // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log + error_log( '[ton-italia-registration] ' . $message ); + } + } + + /** + * @param mixed $value Submitted API key. + * @return string + */ + public static function sanitize_api_key( $value ) { + $value = sanitize_text_field( wp_unslash( (string) $value ) ); + $old = (string) get_option( 'ton_reg_mailchimp_api_key', '' ); + + if ( '' === $value ) { + return $old; + } + + if ( ! preg_match( '/^.+-[a-z]{2}\d+$/i', $value ) ) { + add_settings_error( + 'ton_reg_mailchimp_api_key', + 'invalid_mailchimp_api_key', + __( 'Formato API key Mailchimp non valido.', 'ton-italia-registration' ), + 'error' + ); + return $old; + } + + return $value; + } + + /** + * @param mixed $value Submitted list ID. + * @return string + */ + public static function sanitize_list_id( $value ) { + $value = sanitize_text_field( wp_unslash( (string) $value ) ); + if ( '' === $value || self::is_valid_list_id( $value ) ) { + return $value; + } + + add_settings_error( + 'ton_reg_mailchimp_list_id', + 'invalid_mailchimp_list_id', + __( 'List ID Mailchimp non valido.', 'ton-italia-registration' ), + 'error' + ); + + return (string) get_option( 'ton_reg_mailchimp_list_id', '' ); + } +} diff --git a/includes/class-plugin.php b/includes/class-plugin.php index 41c549b..f6e5af3 100644 --- a/includes/class-plugin.php +++ b/includes/class-plugin.php @@ -39,6 +39,8 @@ TON_Reg_Registration_Form::register(); TON_Reg_Registration_Handler::register(); + add_action( TON_Reg_Mailchimp::CRON_HOOK, array( 'TON_Reg_Mailchimp', 'sync_registration' ) ); + add_action( 'update_option_ton_reg_mailchimp_api_key', array( 'TON_Reg_Mailchimp', 'ensure_api_key_no_autoload' ) ); if ( is_admin() ) { TON_Reg_Admin::register(); @@ -69,6 +71,30 @@ $db_version = '1.2'; } + if ( version_compare( $db_version, '1.3', '<' ) ) { + TON_Reg_Database::create_table(); + + $mailchimp_options = array( + 'ton_reg_mailchimp_enabled', + 'ton_reg_mailchimp_api_key', + 'ton_reg_mailchimp_list_id', + 'ton_reg_mailchimp_tags', + 'ton_reg_mailchimp_permission_ids', + ); + $defaults = TON_Reg_Defaults::options(); + foreach ( $mailchimp_options as $key ) { + if ( false === get_option( $key ) && isset( $defaults[ $key ] ) ) { + add_option( $key, $defaults[ $key ], '', 'ton_reg_mailchimp_api_key' === $key ? 'no' : 'yes' ); + } + } + + if ( get_option( 'ton_reg_mailchimp_api_key' ) ) { + TON_Reg_Mailchimp::ensure_api_key_no_autoload(); + } + + $db_version = '1.3'; + } + update_option( 'ton_reg_db_version', $db_version ); } diff --git a/includes/class-registration-handler.php b/includes/class-registration-handler.php index 420782d..e90cd57 100644 --- a/includes/class-registration-handler.php +++ b/includes/class-registration-handler.php @@ -102,6 +102,19 @@ TON_Reg_Mailer::send_admin_notification( $registration, $user_id ); TON_Reg_Mailer::send_user_confirmation( $registration, $user_id ); + /** + * Fires after a registration is stored and notification emails are sent. + * + * @param int $reg_id Registration ID. + * @param array $data Sanitized form data. + * @param object $registration Registration row. + */ + do_action( 'ton_reg_registration_complete', $reg_id, $data, $registration ); + + if ( ! empty( $data['consenso_newsletter'] ) && TON_Reg_Mailchimp::is_configured() ) { + TON_Reg_Mailchimp::schedule_sync( $reg_id ); + } + $success_url = add_query_arg( array( 'ton_reg' => 'success', diff --git a/languages/ton-italia-registration-it_IT.po b/languages/ton-italia-registration-it_IT.po index 995e66e..d7b1611 100644 --- a/languages/ton-italia-registration-it_IT.po +++ b/languages/ton-italia-registration-it_IT.po @@ -1,7 +1,7 @@ # Italian translations for TON Italia Registration msgid "" msgstr "" -"Project-Id-Version: TON Italia Registration 1.5\n" +"Project-Id-Version: TON Italia Registration 1.6.1\n" "Language: it_IT\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff --git a/readme.txt b/readme.txt index 4c40cee..df156d4 100644 --- a/readme.txt +++ b/readme.txt @@ -4,7 +4,7 @@ Requires at least: 6.0 Tested up to: 6.7 Requires PHP: 8.0 -Stable tag: 1.5 +Stable tag: 1.6.1 License: GPLv2 or later Form di iscrizione socio per TON ITALIA ODV con gestione ammissioni, GDPR e CAPTCHA integrato. @@ -24,6 +24,7 @@ * Email di notifica admin e conferma utente * Pannello admin: elenco, dettaglio, stato Ammesso / Non ammesso, data Libro Associati * Strumenti GDPR: export JSON, anonimizzazione, eliminazione definitiva +* Integrazione Mailchimp opzionale (consenso newsletter) == Installation == @@ -61,6 +62,14 @@ == Changelog == += 1.6.1 = +* Corretto test connessione Mailchimp (form dedicato, evita pagina bianca) + += 1.6 = +* Integrazione Mailchimp API v3: iscrizione automatica su consenso newsletter +* Impostazioni admin: API key, List ID, tag, test connessione +* Stato sincronizzazione Mailchimp in dettaglio iscrizione + retry manuale + = 1.5 = * Aggiunto caricamento documento «Ricevuta pagamento» in admin diff --git a/ton-italia-registration.php b/ton-italia-registration.php index d46e7a0..1d09bc0 100644 --- a/ton-italia-registration.php +++ b/ton-italia-registration.php @@ -3,7 +3,7 @@ * Plugin Name: TON Italia Registration * Plugin URI: https://www.tentofnations.it/ * Description: Form iscrizione socio TON ITALIA ODV con GDPR, CAPTCHA integrato e gestione ammissioni. - * Version: 1.5 + * Version: 1.6.1 * Author: Fabio Arrigoni * Text Domain: ton-italia-registration * Domain Path: /languages @@ -15,7 +15,7 @@ defined( 'ABSPATH' ) || exit; -define( 'TON_REG_VERSION', '1.5' ); +define( 'TON_REG_VERSION', '1.6.1' ); define( 'TON_REG_PLUGIN_FILE', __FILE__ ); define( 'TON_REG_PLUGIN_DIR', plugin_dir_path( __FILE__ ) ); define( 'TON_REG_PLUGIN_URL', plugin_dir_url( __FILE__ ) );