AUDIENCE_ADDAUSER

Class AUDIENCE_ADDAUSER

Contents

  • Methods

  • 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