Changed source root directory

This commit is contained in:
2026-03-05 16:30:11 +01:00
parent dc85447ee1
commit 538f85d7a2
5868 changed files with 749734 additions and 99 deletions

View File

@@ -0,0 +1,45 @@
<?php
/**
* Email extraction handler.
*
* @package contact-form-7-mailchimp-extension
* @author renzo.johnson@gmail.com
* @copyright 2014-2026 https://renzojohnson.com
* @license GPL-3.0+
*/
defined( 'ABSPATH' ) || exit;
class Cmatic_Email_Extractor {
private const TAG_PATTERN = '/\[\s*([a-zA-Z_][0-9a-zA-Z:._-]*)\s*\]/';
public static function extract( array $cf7_mch, array $posted_data ): string {
if ( empty( $cf7_mch['merge_fields'] ) || ! is_array( $cf7_mch['merge_fields'] ) ) {
return '';
}
foreach ( $cf7_mch['merge_fields'] as $idx => $merge_field ) {
if ( ( $merge_field['tag'] ?? '' ) === 'EMAIL' ) {
$field_key = 'field' . ( $idx + 3 );
if ( ! empty( $cf7_mch[ $field_key ] ) ) {
return self::replace_tags( $cf7_mch[ $field_key ], $posted_data );
}
break;
}
}
return '';
}
public static function replace_tags( string $subject, array $posted_data ): string {
if ( preg_match( self::TAG_PATTERN, $subject, $matches ) > 0 ) {
if ( isset( $posted_data[ $matches[1] ] ) ) {
$submitted = $posted_data[ $matches[1] ];
return is_array( $submitted ) ? implode( ', ', $submitted ) : $submitted;
}
return $matches[0];
}
return $subject;
}
}

View File

@@ -0,0 +1,54 @@
<?php
/**
* Mailchimp subscriber service.
*
* @package contact-form-7-mailchimp-extension
* @author renzo.johnson@gmail.com
* @copyright 2014-2026 https://renzojohnson.com
* @license GPL-3.0+
*/
defined( 'ABSPATH' ) || exit;
class Cmatic_Mailchimp_Subscriber {
public static function subscribe( string $api_key, string $list_id, string $email, string $status, array $merge_vars, int $form_id, Cmatic_File_Logger $logger ): void {
try {
$logger->log( 'INFO', 'Starting subscription process.', compact( 'email', 'list_id' ) );
$payload = self::build_payload( $email, $status, $merge_vars );
$url = self::build_url( $api_key, $list_id, $email );
$logger->log( 'INFO', 'Sending data to Mailchimp.', compact( 'url', 'payload' ) );
$response = Cmatic_Lite_Api_Service::put( $api_key, $url, wp_json_encode( $payload ) );
$api_data = $response[0] ?? array();
$logger->log( 'INFO', 'Mailchimp API Response.', $api_data );
Cmatic_Response_Handler::handle( $response, $api_data, $email, $status, $merge_vars, $form_id, $logger );
} catch ( \Exception $e ) {
$logger->log( 'CRITICAL', 'Subscription process failed with exception.', $e->getMessage() );
Cmatic_Submission_Feedback::set_result( Cmatic_Submission_Feedback::failure( 'network_error', $e->getMessage(), $email ) );
}
}
private static function build_payload( string $email, string $status, array $merge_vars ): array {
$payload = array(
'email_address' => $email,
'status' => $status,
);
if ( ! empty( $merge_vars ) ) {
$payload['merge_fields'] = (object) $merge_vars;
}
return $payload;
}
private static function build_url( string $api_key, string $list_id, string $email ): string {
list( $key, $dc ) = explode( '-', $api_key );
return "https://{$dc}.api.mailchimp.com/3.0/lists/{$list_id}/members/" . md5( strtolower( $email ) );
}
}

View File

@@ -0,0 +1,53 @@
<?php
/**
* Merge variables builder.
*
* @package contact-form-7-mailchimp-extension
* @author renzo.johnson@gmail.com
* @copyright 2014-2026 https://renzojohnson.com
* @license GPL-3.0+
*/
defined( 'ABSPATH' ) || exit;
class Cmatic_Merge_Vars_Builder {
public static function build( array $cf7_mch, array $posted_data ): array {
$merge_vars = array();
if ( empty( $cf7_mch['merge_fields'] ) || ! is_array( $cf7_mch['merge_fields'] ) ) {
return $merge_vars;
}
$field_index = 3;
$max_index = CMATIC_LITE_FIELDS + 2;
foreach ( $cf7_mch['merge_fields'] as $merge_field ) {
$field_key = 'field' . $field_index;
$merge_tag = $merge_field['tag'] ?? '';
if ( ! empty( $cf7_mch[ $field_key ] ) && ! empty( $merge_tag ) ) {
$value = Cmatic_Email_Extractor::replace_tags( $cf7_mch[ $field_key ], $posted_data );
if ( ! empty( $value ) ) {
$merge_vars[ $merge_tag ] = $value;
}
}
++$field_index;
if ( $field_index > $max_index ) {
break;
}
}
return self::filter_empty( $merge_vars );
}
private static function filter_empty( array $merge_vars ): array {
return array_filter(
$merge_vars,
function ( $value ) {
return ! empty( $value ) || 0 === $value || '0' === $value;
}
);
}
}

View File

@@ -0,0 +1,83 @@
<?php
/**
* API response handler.
*
* @package contact-form-7-mailchimp-extension
* @author renzo.johnson@gmail.com
* @copyright 2014-2026 https://renzojohnson.com
* @license GPL-3.0+
*/
defined( 'ABSPATH' ) || exit;
class Cmatic_Response_Handler {
public static function handle( array $response, array $api_data, string $email, string $status, array $merge_vars, int $form_id, Cmatic_File_Logger $logger ): void {
// Network failure.
if ( false === $response[0] ) {
$logger->log( 'ERROR', 'Network request failed.', array( 'response' => $response[1] ) );
Cmatic_Submission_Feedback::set_result( Cmatic_Submission_Feedback::failure( 'network_error', '', $email ) );
return;
}
// Empty response.
if ( empty( $api_data ) ) {
$logger->log( 'ERROR', 'Empty API response received.' );
Cmatic_Submission_Feedback::set_result( Cmatic_Submission_Feedback::failure( 'api_error', 'Empty response from Mailchimp API.', $email ) );
return;
}
// API errors array.
if ( ! empty( $api_data['errors'] ) ) {
self::log_api_errors( $api_data['errors'] );
Cmatic_Submission_Feedback::set_result( Cmatic_Submission_Feedback::parse_api_error( $api_data, $email ) );
return;
}
// HTTP error status.
if ( isset( $api_data['status'] ) && is_int( $api_data['status'] ) && $api_data['status'] >= 400 ) {
Cmatic_Submission_Feedback::set_result( Cmatic_Submission_Feedback::parse_api_error( $api_data, $email ) );
return;
}
// Error in title.
if ( isset( $api_data['title'] ) && stripos( $api_data['title'], 'error' ) !== false ) {
Cmatic_Submission_Feedback::set_result( Cmatic_Submission_Feedback::parse_api_error( $api_data, $email ) );
return;
}
// Success!
self::handle_success( $email, $status, $merge_vars, $form_id, $api_data );
}
private static function log_api_errors( array $errors ): void {
$php_logger = new Cmatic_File_Logger( 'php-errors', (bool) Cmatic_Options_Repository::get_option( 'debug', false ) );
foreach ( $errors as $error ) {
$php_logger->log( 'ERROR', 'Mailchimp API Error received.', $error );
}
}
private static function handle_success( string $email, string $status, array $merge_vars, int $form_id, array $api_data ): void {
self::increment_counter( $form_id );
self::track_test_modal();
Cmatic_Submission_Feedback::set_result( Cmatic_Submission_Feedback::success( $email, $status, $merge_vars, $api_data ) );
do_action( 'cmatic_subscription_success', $form_id, $email );
}
private static function track_test_modal(): void {
if ( isset( $_POST['_cmatic_test_modal'] ) && '1' === $_POST['_cmatic_test_modal'] ) {
Cmatic_Options_Repository::set_option( 'features.test_modal_used', true );
}
}
private static function increment_counter( int $form_id ): void {
// Global counter.
$count = (int) Cmatic_Options_Repository::get_option( 'stats.sent', 0 );
Cmatic_Options_Repository::set_option( 'stats.sent', $count + 1 );
// Per-form counter.
$cf7_mch = get_option( 'cf7_mch_' . $form_id, array() );
$cf7_mch['stats_sent'] = ( (int) ( $cf7_mch['stats_sent'] ?? 0 ) ) + 1;
update_option( 'cf7_mch_' . $form_id, $cf7_mch );
}
}

View File

@@ -0,0 +1,39 @@
<?php
/**
* Subscription status resolver.
*
* @package contact-form-7-mailchimp-extension
* @author renzo.johnson@gmail.com
* @copyright 2014-2026 https://renzojohnson.com
* @license GPL-3.0+
*/
defined( 'ABSPATH' ) || exit;
class Cmatic_Status_Resolver {
public static function resolve( array $cf7_mch, array $posted_data, Cmatic_File_Logger $logger ): ?string {
// Double opt-in enabled (per-form setting).
if ( ! empty( $cf7_mch['double_optin'] ) || ! empty( $cf7_mch['confsubs'] ) ) {
return 'pending';
}
// Acceptance checkbox required.
if ( ! empty( $cf7_mch['accept'] ) ) {
$acceptance = Cmatic_Email_Extractor::replace_tags( $cf7_mch['accept'], $posted_data );
if ( empty( $acceptance ) ) {
// Add as unsubscribed if configured.
if ( ! empty( $cf7_mch['addunsubscr'] ) ) {
return 'unsubscribed';
}
$logger->log( 'INFO', 'Subscription skipped: acceptance checkbox was not checked.' );
Cmatic_Submission_Feedback::set_result( Cmatic_Submission_Feedback::skipped( 'acceptance_not_checked' ) );
return null;
}
}
return 'subscribed';
}
}