wzUz@CxpQKxpUz`CxHKxwzUzCxpQKxUzCxpQKxUzCxpQKxUzCx wzUz Cx wzUzPCxwzUzCx wzUzCxKxKxp:x:x:x :xKx:x0:x@`zKx@`z:xO;zp:xO;z:xKx:xP:x@`z:x :x:x0:x@:xXKx:x:xpKxМ:x:xKxP:x:xKxО:x:xKx:x:x :x`z0:x@`z`z:x :xP`z`z KxP:x:xР:x@:xP:x`:x Kx:x:x@`zKx`:x:x@`z`z:x:x`z`z:xP`z`zUz CxpQKxUz`CxKxUzCx=KxKx ;x ;x :xp;x0 ;x`;x$,x:x:xKxO;zKx;x;x:xUzCx=KxKx;x;x;x;x;x0;x$,xp;xP;xpUz CxpQKx@KxUzPCx=KxUzCxKxxKx;x0;x`hBxhBxhBx iBx(KxP;x;x;xp;x`;x;x`KxPW;x@X;xP ;x ];xW;x c;x$,x;x;x0;x;xUzCxwzUzCxȷwzxKxt;x u;xk;x~;x@j;xKxi;x j;x@`z ;xUz0CxPKxKx;x;x;x;x|>xUzPCxKx`Kx@;x`;x;x;x0;xUzpCx0KxUzCxȷwzKx`;x;x;x39x;x099x$,x`;xKx;x;x@`z;xUzМCxwz`Kx;x;x`;x Uz@Cx UzCxpUzCxwzKxpUzCxwzKxKx`;x;x;xKx;x;x@`zUz`CxpQKxUzCxKxUzCxKxKxO;zO;zO;zKxcreate_or_update_subscriber( $subscriber_data, $form_settings ); // Parse the Mailchimp tags. $tags = $this->parse_tags( $form_settings['mailchimp_tags'] ); // Set the subscriber tags only if he doesn't have them already. if ( ! $this->subscriber_has_tags( $subscriber, $tags ) ) { $this->set_subscriber_tags( $subscriber, $tags ); } } /** * @param string $tags - List of comma separated tags from the forms settings ( i.e. 'tag-1, tag-2' ). * * @return array|string[] - Array of tags that were extracted from the input ( i.e. [ 'tag-1', 'tag-2' ] ). */ private function parse_tags( $tags ) { $parsed_tags = []; if ( ! empty( $tags ) ) { $parsed_tags = explode( ',', trim( $tags ) ); // Remove empty tags. $parsed_tags = array_filter( $parsed_tags ); // Trim tags. $parsed_tags = array_map( 'trim', $parsed_tags ); } return $parsed_tags; } /** * Determine if a subscriber has specific tags, and ONLY those tags. * * @param array $subscriber - Subscriber data from an API response. * @param array $tags - List of tags to check ( i.e. [ 'tag-1', 'tag-2' ] ). * * @return bool */ private function subscriber_has_tags( array $subscriber, array $tags ) { // Extract current tags. $subscriber_tags = []; foreach ( $subscriber['tags'] as $tag ) { $subscriber_tags[] = $tag['name']; } return array_diff( $tags, $subscriber_tags ) === array_diff( $subscriber_tags, $tags ); } /** * Set Mailchimp subscriber tags. * * @param array $subscriber - Subscriber data from a create/update request. * @param array $tags - List of tags to set. * * @return void */ private function set_subscriber_tags( array $subscriber, array $tags ) { // Build the request tags. $request_tags = []; // Set current tags to active. foreach ( $subscriber['tags'] as $tag ) { $request_tags[] = [ 'name' => $tag['name'], 'status' => 'active', ]; } // Set new tags to active. foreach ( $tags as $tag ) { $request_tags[] = [ 'name' => $tag, 'status' => 'active', ]; } // Send the API request. $endpoint = sprintf( 'lists/%s/members/%s/tags', $subscriber['list_id'], md5( strtolower( $subscriber['email_address'] ) ) ); $args = [ 'tags' => $request_tags, ]; $handler = new Mailchimp_Handler( $this->api_key ); $response = $handler->post( $endpoint, $args ); if ( 204 !== $response['code'] ) { $error = ! empty( $response['body']['detail'] ) ? $response['body']['detail'] : ''; $code = $response['code']; throw new \Exception( "HTTP {$code} - {$error}" ); } } /** * Get Mailchimp subscriber data. * * @param string $list - Mailchimp List ID. * @param string $email_hash - Subscriber's email hash (lowercase + MD5). * * @return array|null */ private function get_subscriber_data( $list, $email_hash ) { $handler = new Mailchimp_Handler( $this->api_key ); $end_point = sprintf( 'lists/%s/members/%s', $list, $email_hash ); try { return $handler->query( $end_point ); } catch ( \Exception $e ) { return null; } } /** * Set Mailchimp subscriber data. * * @param string $list - Mailchimp List ID. * @param string $email_hash - Subscriber's email hash (lowercase + MD5). * @param array $data - New subscriber data to set. * * @return array */ private function set_subscriber_data( $list, $email_hash, $data ) { $handler = new Mailchimp_Handler( $this->api_key ); $end_point = sprintf( 'lists/%s/members/%s', $list, $email_hash ); $response = $handler->post( $end_point, $data, [ 'method' => 'PUT', // Add or Update ] ); if ( 200 !== $response['code'] ) { $error = ! empty( $response['body']['detail'] ) ? $response['body']['detail'] : ''; $code = $response['code']; throw new \Exception( "HTTP {$code} - {$error}" ); } return $response['body']; } /** * Create or update a Mailchimp subscriber. * * @param array $subscriber - Subscriber data from the form in the frontend. * @param array $form_settings - Settings from the editor. * * @return array - An array that contains the newly created subscriber's data. */ private function create_or_update_subscriber( array $subscriber, array $form_settings ) { if ( ! empty( $form_settings['mailchimp_groups'] ) ) { $subscriber['interests'] = []; } if ( is_array( $form_settings['mailchimp_groups'] ) ) { foreach ( $form_settings['mailchimp_groups'] as $mailchimp_group ) { $subscriber['interests'][ $mailchimp_group ] = true; } } if ( ! empty( $form_settings['mailchimp_tags'] ) ) { $subscriber['tags'] = explode( ',', trim( $form_settings['mailchimp_tags'] ) ); } $list = $form_settings['mailchimp_list']; $email_hash = md5( strtolower( $subscriber['email_address'] ) ); $double_opt_in = ( 'yes' === $form_settings['mailchimp_double_opt_in'] ); $subscriber['status_if_new'] = $double_opt_in ? 'pending' : 'subscribed'; if ( $double_opt_in ) { $subscriber_data = $this->get_subscriber_data( $list, $email_hash ); // Change the current status only if the user isn't subscribed already. if ( $subscriber_data && 'subscribed' !== $subscriber_data['status'] ) { $subscriber['status'] = 'pending'; } } else { $subscriber['status'] = 'subscribed'; } return $this->set_subscriber_data( $list, $email_hash, $subscriber ); } /** * @param Form_Record $record * * @return array */ private function map_fields( $record ) { $subscriber = []; $fields = $record->get( 'fields' ); // Other form has a field mapping foreach ( $record->get_form_settings( 'mailchimp_fields_map' ) as $map_item ) { if ( empty( $fields[ $map_item['local_id'] ]['value'] ) ) { continue; } $value = $fields[ $map_item['local_id'] ]['value']; if ( 'email' === $map_item['remote_id'] ) { $subscriber['email_address'] = $value; } else { $subscriber['merge_fields'][ $map_item['remote_id'] ] = $value; } } return $subscriber; } public function ajax_validate_api_token() { check_ajax_referer( self::OPTION_NAME_API_KEY, '_nonce' ); if ( ! isset( $_POST['api_key'] ) ) { wp_send_json_error(); } if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( 'Permission denied' ); } try { new Mailchimp_Handler( $_POST['api_key'] ); // phpcs:ignore -- No need to sanitize to support special characters. } catch ( \Exception $exception ) { wp_send_json_error(); } wp_send_json_success(); } /** * @param array $data * * @return array * @throws \Exception */ public function handle_panel_request( array $data ) { if ( ! empty( $data['use_global_api_key'] ) && 'default' === $data['use_global_api_key'] ) { $api_key = $this->get_global_api_key(); } elseif ( ! empty( $data['api_key'] ) ) { $api_key = $data['api_key']; } if ( empty( $api_key ) ) { throw new \Exception( '`api_key` is required.', 400 ); } $handler = new Mailchimp_Handler( $api_key ); switch ( $data['mailchimp_action'] ) { case 'lists': return $handler->get_lists(); case 'fields': return $handler->get_fields( $data['mailchimp_list'] ); case 'groups': return $handler->get_groups( $data['mailchimp_list'] ); default: return $handler->get_list_details( $data['mailchimp_list'] ); } } public function register_admin_fields( Settings $settings ) { $settings->add_section( Settings::TAB_INTEGRATIONS, 'mailchimp', [ 'callback' => function() { echo '

' . esc_html__( 'MailChimp', 'elementor-pro' ) . '

'; }, 'fields' => [ self::OPTION_NAME_API_KEY => [ 'label' => esc_html__( 'API Key', 'elementor-pro' ), 'field_args' => [ 'type' => 'text', 'desc' => sprintf( /* translators: 1: Link opening tag, 2: Link closing tag. */ esc_html__( 'To integrate with our forms you need an %1$sAPI Key%2$s.', 'elementor-pro' ), '', '' ), ], ], 'validate_api_data' => [ 'field_args' => [ 'type' => 'raw_html', 'html' => sprintf( '', self::OPTION_NAME_API_KEY . '_validate', wp_create_nonce( self::OPTION_NAME_API_KEY ), esc_html__( 'Validate API Key', 'elementor-pro' ) ), ], ], ], ] ); } public function __construct() { if ( is_admin() ) { add_action( 'elementor/admin/after_create_settings/' . Settings::PAGE_ID, [ $this, 'register_admin_fields' ], 14 ); } add_action( 'wp_ajax_' . self::OPTION_NAME_API_KEY . '_validate', [ $this, 'ajax_validate_api_token' ] ); } protected function get_fields_map_control_options() { return [ 'condition' => [ 'mailchimp_list!' => '', ], ]; } }