AUDIENCE_ADDAUSER

Class AUDIENCE_ADDAUSER


Source Source

File: src/integrations/mailchimp/actions/audience-addauser.php

class AUDIENCE_ADDAUSER {
	/**
	 * Integration code
	 *
	 * @var string
	 */
	public static $integration = 'MAILCHIMP';
	private $action_code;
	private $action_meta;
	/**
	 * Set up Automator action constructor.
	 */
	public function __construct() {
		$this->action_code = 'MCHIMPAUDIENCEADDAUSER';
		$this->action_meta = 'AUDIENCEADDAUSER';
		$this->define_action();
	}
	/**
	 * Define and register the action by pushing it into the Automator object
	 */
	public function define_action() {
		global $uncanny_automator;
		$action = array(
			'author'             => $uncanny_automator->get_author_name( $this->action_code ),
			'support_link'       => $uncanny_automator->get_author_support_link( $this->action_code, 'knowledge-base/mailchimp/' ),
			'is_pro'             => false,
			'integration'        => self::$integration,
			'code'               => $this->action_code,
			'sentence'           => sprintf( __( 'Add the user to {{an audience:%1$s}}', 'uncanny-automator' ), $this->action_meta ),
			'select_option_name' => __( 'Add the user to {{an audience}}', 'uncanny-automator' ),
			'priority'           => 10,
			'accepted_args'      => 1,
			'execution_function' => array( $this, 'add_update_audience_member' ),
			'options_group'      => array(
				$this->action_meta => array(
					$uncanny_automator->helpers->recipe->mailchimp->options->get_all_lists(
						__( 'Audience', 'uncanny-automator' ),
						'MCLIST',
						array(
							'is_ajax'      => true,
							'target_field' => 'MCLISTGROUPS',
							'endpoint'     => 'select_mcgroupslist_from_mclist',
						)
					),
					$uncanny_automator->helpers->recipe->mailchimp->options->get_double_opt_in(
						__( 'Double opt-in', 'uncanny-automator' ),
						'MCDOUBLEOPTIN',
						array(
							'description' => __( 'When set to "yes", a confirmation email will be sent before the user is added to the selected audience.', 'uncanny-automator' ),
						)
					),
					$uncanny_automator->helpers->recipe->mailchimp->options->get_double_opt_in(
						__( 'Update existing', 'uncanny-automator' ),
						'MCUPDATEEXISTING',
						array(
							'description' => __( 'If this is set to Yes, the information provided will be used to update the existing user. Fields that are left blank will not be updated.', 'uncanny-automator' ),
						)
					),
					$uncanny_automator->helpers->recipe->mailchimp->options->get_double_opt_in(
						__( 'Change groups?', 'uncanny-automator' ),
						'MCCHANGEGROUPS',
						array(
							'options'     => array(
								'replace-all'      => __( 'Replace all', 'uncanny-automator' ),
								'add-only'         => __( 'Add only', 'uncanny-automator' ),
								'replace-matching' => __( 'Replace matching', 'uncanny-automator' ),
							),
							'description' => __( "Add only: The group(s) specified below will be added to the subscriber's existing groups/interests. Replace All: All of the subscriber's existing groups will be cleared, and replaced with the groups selected below. Replace Matching: Clears any existing group selections only for the groups specified below.", 'uncanny-automator' ),
						)
					),
					$uncanny_automator->helpers->recipe->mailchimp->options->get_list_groups(
						__( 'Groups', 'uncanny-automator' ),
						'MCLISTGROUPS',
						array(
							// 'is_ajax'     => TRUE,
							'required' => false,
						)
					),
					$uncanny_automator->helpers->recipe->field->text_field( 'MCLANGUAGECODE', __( 'Language code', 'uncanny-automator' ), true, 'text', null, false ),
					array(
						'option_code'       => 'MERGE_FIELDS',
						'input_type'        => 'repeater',
						'label'             => __( 'Merge fields', 'uncanny-automator' ),
						/* translators: 1. Button */
						'description'       => __( '', 'uncanny-automator' ),
						'required'          => true,
						'fields'            => array(
							array(
								'option_code' => 'FIELD_NAME',
								'label'       => __( 'Field', 'uncanny-automator' ),
								'input_type'  => 'text',
								'required'    => true,
								'read_only'   => true,
								'options'     => array(),
							),
							$uncanny_automator->helpers->recipe->field->text_field( 'FIELD_VALUE', __( 'Value', 'uncanny-automator' ), true, 'text', '', false ),
						),
						'add_row_button'    => __( 'Add pair', 'uncanny-automator' ),
						'remove_row_button' => __( 'Remove pair', 'uncanny-automator' ),
						'hide_actions'      => true,
					),
				),
			),
			'buttons'            => array(
				array(
					'show_in'     => $this->action_meta,
					'text'        => __( 'Load fields', 'uncanny-automator' ),
					'css_classes' => 'uap-btn uap-btn--red',
					'on_click'    => $this->get_samples_js(),
					'modules'     => array( 'modal', 'markdown' ),
				),
			),
		);
		$uncanny_automator->register->action( $action );
	}

	public function get_samples_js() {
		// Start output
		ob_start();
		// It's optional to add the <script> tags
		// This must have only one anonymous function
		?>
		<script>
			// Do when the user clicks on send test
			function ($button, data, modules) {
				// Create a configuration object
				let config = {
					// In milliseconds, the time between each call
					timeBetweenCalls: 1 * 1000,
					// In milliseconds, the time we're going to check for samples
					checkingTime: 60 * 1000,
					// Links
					links: {
						noResultsSupport: 'https://automatorplugin.com/knowledge-base/google-sheets/'
					},
					// i18n
					i18n: {
						checkingHooks: "<?php printf( __( "We're checking for columns. We'll keep trying for %s seconds.", 'uncanny-automator' ), '{{time}}' ); ?>",
						noResultsTrouble: "<?php _e( 'We had trouble finding columns.', 'uncanny-automator' ); ?>",
						noResultsSupport: "<?php _e( 'See more details or get help', 'uncanny-automator' ); ?>",
						samplesModalTitle: "<?php _e( "Here is the data we've collected", 'uncanny-automator' ); ?>",
						samplesModalWarning: "<?php /* translators: 1. Button */ printf( __( 'Clicking on \"%1$s\" will remove your current fields and will use the ones on the table above instead.', 'uncanny-automator' ), '{{confirmButton}}' ); ?>",
						samplesTableValueType: "<?php _e( 'Value type', 'uncanny-automator' ); ?>",
						samplesTableReceivedData: "<?php _e( 'Received data', 'uncanny-automator' ); ?>",
						samplesModalButtonConfirm: "<?php /* translators: Non-personal infinitive verb */ _e( 'Use these fields', 'uncanny-automator' ); ?>",
						samplesModalButtonCancel: "<?php /* translators: Non-personal infinitive verb */ _e( 'Do nothing', 'uncanny-automator' ); ?>",
					}
				}
				// Create the variable we're going to use to know if we have to keep doing calls
				let foundResults = false
				// Get the date when this function started
				let startDate = new Date()
				// Create array with the data we're going to send
				let dataToBeSent = {
					action: 'get_mailchimp_audience_fields',
					nonce: UncannyAutomator.nonce,
					recipe_id: UncannyAutomator.recipe.id,
					item_id: data.item.id,
					audience: data.values.MCLIST
				}
				// Add notice to the item
				// Create notice
				let $notice = jQuery('<div/>', {
					'class': 'item-options__notice item-options__notice--warning'
				})
				// Add notice message
				$notice.html(config.i18n.checkingHooks.replace('{{time}}', parseInt(config.checkingTime / 1000)))
				// Get the notices container
				let $noticesContainer = jQuery('.item[data-id="' + data.item.id + '"] .item-options__notices')
				// Add notice
				$noticesContainer.html($notice)
				// Create the function we're going to use recursively to
				// do check for the samples
				var getSamples = function () {
					// Do AJAX call
					jQuery.ajax({
						method: 'POST',
						dataType: 'json',
						url: ajaxurl,
						data: dataToBeSent,
						// Set the checking time as the timeout
						timeout: config.checkingTime,
						success: function (response) {
							// Get new date
							let currentDate = new Date()
							// Define the default value of foundResults
							let foundResults = false
							// Check if the response was successful
							if (response.success) {
								// Check if we got the rows from a sample
								if (response.samples.length > 0) {
									// Update foundResults
									foundResults = true
								}
							}
							// Check if we have to do another call
							let shouldDoAnotherCall = false
							// First, check if we don't have results
							if (!foundResults) {
								// Check if we still have time left
								if ((currentDate.getTime() - startDate.getTime()) <= config.checkingTime) {
									// Update result
									shouldDoAnotherCall = true
								}
							}
							if (shouldDoAnotherCall) {
								// Wait and do another call
								setTimeout(function () {
									// Invoke this function again
									getSamples()
								}, config.timeBetweenCalls)
							} else {
								// Add loading animation to the button
								$button.removeClass('uap-btn--loading uap-btn--disabled')
								// Iterate samples and create an array with the rows
								let rows = []
								let keys = {}
								jQuery.each(response.samples, function (index, sample) {
									// Iterate keys
									jQuery.each(sample, function (index, row) {
										// Check if the we already added this key
										if (typeof keys[row.key] !== 'undefined') {
											// Then just append the value
											// rows[ keys[ row.key ] ].data = rows[ keys[ row.key ] ].data + ', ' + row.data;
										} else {
											// Add row and save the index
											keys[row.key] = rows.push(row)
										}
									})
								})
								// Get the field with the fields (WEBHOOK_DATA)
								let mergeFields = data.item.options.AUDIENCEADDAUSER.fields[6]
								// Remove all the current fields
								mergeFields.fieldRows = []
								// Add new rows. Iterate rows from the sample
								jQuery.each(rows, function (index, row) {
									// Add row
									mergeFields.addRow({
										FIELD_NAME: row.key
									}, false)
								})
								// Render again
								mergeFields.reRender()
								// Check if it has results
								if (foundResults) {
									// Remove notice
									$notice.remove()
								} else {
									// Change the notice type
									$notice.removeClass('item-options__notice--warning').addClass('item-options__notice--error')
									// Create a new notice message
									let noticeMessage = config.i18n.noResultsTrouble
									// Change the notice message
									$notice.html(noticeMessage + ' ')
									// Add help link
									let $noticeHelpLink = jQuery('<a/>', {
										target: '_blank',
										href: config.links.noResultsSupport
									}).text(config.i18n.noResultsSupport)
									$notice.append($noticeHelpLink)
								}
							}
						},
						statusCode: {
							403: function () {
								location.reload()
							}
						},
						fail: function (response) {
						}
					})
				}
				// Add loading animation to the button
				$button.addClass('uap-btn--loading uap-btn--disabled')
				// Try to get samples
				getSamples()
			}
		</script>
		<?php
		// Get output
		$output = ob_get_clean();
		// Return output
		return $output;
	}
	/**
	 * Validation function when the action is hit
	 *
	 * @param $user_id
	 * @param $action_data
	 * @param $recipe_id
	 */
	public function add_update_audience_member( $user_id, $action_data, $recipe_id, $args ) {
		global $uncanny_automator;
		try {
			$mc_client = $uncanny_automator->helpers->recipe->mailchimp->options->get_mailchimp_client();
			if ( $mc_client ) {
				$list_id         = $action_data['meta']['MCLIST'];
				$double_optin    = $action_data['meta']['MCDOUBLEOPTIN'];
				$update_existing = $action_data['meta']['MCUPDATEEXISTING'];
				$change_groups   = $action_data['meta']['MCCHANGEGROUPS'];
				$list_groups     = json_decode( $action_data['meta']['MCLISTGROUPS'] );
				$lang_code       = $uncanny_automator->parse->text( $action_data['meta']['MCLANGUAGECODE'], $recipe_id, $user_id, $args );
				$merge_fields = $action_data['meta']['MERGE_FIELDS'];
				$fields       = json_decode( $merge_fields, true );
				$key_values   = array();
				for ( $i = 0; $i < count( $fields ); $i ++ ) {
					$key   = $fields[ $i ]['FIELD_NAME'];
					$value = $uncanny_automator->parse->text( $fields[ $i ]['FIELD_VALUE'], $recipe_id, $user_id, $args );
					if ( strpos( $key, '_addr1' ) || strpos( $key, '_addr2' ) || strpos( $key, '_city' ) || strpos( $key, '_state' ) || strpos( $key, '_zip' ) || strpos( $key, '_country' ) ) {
						$key_split = explode( '_', $key, 2 );
						if ( count( $key_split ) == 2 ) {
							$key_values[ $key_split[0] ][ $key_split[1] ] = $value;
						}
					} else {
						$key_values[ $key ] = $value;
					}
				}
				// get current user email
				$user           = get_userdata( $user_id );
				$user_hash      = md5( strtolower( trim( $user->user_email ) ) );
				$user_interests = array();
				if ( ! empty( $list_groups ) ) {
					foreach ( $list_groups as $group_id ) {
						$user_interests[ $group_id ] = true;
					}
				}
				$request_params = array(
					'action'    => 'get_subscriber',
					'list_id'   => $list_id,
					'user_hash' => $user_hash,
				);
				$response = $uncanny_automator->helpers->recipe->mailchimp->options->api_request( $request_params );
				if ( 200 === $response->statusCode ) {
					if ( 'no' === $update_existing ) {
						$error_msg                           = __( 'User already subscribed to the list.', 'uncanny-automator' );
						$action_data['do-nothing']           = true;
						$action_data['complete_with_errors'] = true;
						$uncanny_automator->complete_action( $user_id, $action_data, $recipe_id, $error_msg );
						return;
					}
					// Apply groups conditions
					if ( ! empty( $response->data->interests ) ) {
						// Replace All. All of the subscriber's existing groups will be cleared, and replaced with the groups selected below.
						if ( 'replace-all' === $change_groups ) {
							foreach ( $response->data->interests as $existing_group => $group_status ) {
								if ( $group_status === true && ! key_exists( $existing_group, $user_interests ) ) {
									$user_interests[ $existing_group ] = false;
								}
							}
						} elseif ( 'replace-matching' === $change_groups ) {
							//Replace Matching. Clears any existing group selections only for the groups specified below.
							foreach ( $existing_sub['interests'] as $existing_group => $group_status ) {
								if ( $group_status === true && key_exists( $existing_group, $user_interests ) ) {
									$user_interests[ $existing_group ] = false;
								}
							}
						}
					}
				}
				// Now create an audience
				$status = 'subscribed';
				if ( 'yes' === $double_optin ) {
					$status = 'pending';
				}
				$user_data = array(
					'email_address' => $user->user_email,
					'status'        => $status,
					'merge_fields'  => $key_values,
					'language'      => $lang_code,
					'interests'     => $user_interests,
				);
				if ( 'yes' === $update_existing ) {
					$user_data['status_if_new'] = $status;
				}
				if ( empty( $user_data['interests'] ) ) {
					unset( $user_data['interests'] );
				}
				$request_params = array(
					'action'    => 'add_subscriber',
					'list_id'   => $list_id,
					'user_hash' => $user_hash,
					'user_data' => json_encode( $user_data ),
				);
				$response = $uncanny_automator->helpers->recipe->mailchimp->options->api_request( $request_params );
				// if add/update failed
				if ( $response->statusCode !== 200 ) {
					$uncanny_automator->helpers->recipe->mailchimp->options->log_action_error( $response, $user_id, $action_data, $recipe_id );
					return;
				}
				$uncanny_automator->complete_action( $user_id, $action_data, $recipe_id );
				return;
			} else {
				// log error when no token found.
				$error_msg                           = __( 'Mailchimp account is not connected.', 'uncanny-automator' );
				$action_data['do-nothing']           = true;
				$action_data['complete_with_errors'] = true;
				$uncanny_automator->complete_action( $user_id, $action_data, $recipe_id, $error_msg );
				return;
			}
		} catch ( \Exception $e ) {
			$error_msg = $e->getMessage();
			if ( $json = json_decode( $error_msg ) ) {
				if ( isset( $json->error ) && isset( $json->error->message ) ) {
					$error_msg = $json->error->message;
				}
			}
			$action_data['do-nothing']           = true;
			$action_data['complete_with_errors'] = true;
			$uncanny_automator->complete_action( $user_id, $action_data, $recipe_id, $error_msg );
			return;
		}
	}

}

Methods Methods