����JFIF��x�x�����C�      ���C  �����"�������������� �������}�!1AQa"q2���#B��R��$3br� %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz�������������������������������������������������������������������������������� ������w�!1AQaq"2�B���� #3R�br� $4�%�&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz������������������������������������������������������������������������ ��?�����N����m?����j����EP��httpsemail/FluentCRM.php000064400000023075152214676150010163 0ustar00 array( 'list_id' => 'id', 'name' => 'title', ), 'subscriber' => array( 'email' => 'email', 'last_name' => 'last_name', 'name' => 'first_name', 'custom_fields' => 'custom_fields', ), 'custom_field' => array( 'field_id' => 'slug', 'name' => 'label', 'type' => 'type', 'hidden' => 'hidden', 'options' => 'options', ), 'custom_field_option' => array( 'id' => 'value', 'name' => 'value', ), 'custom_field_type' => array( // Us <=> Them. 'radio' => 'radio', 'checkbox' => 'checkbox', // Us => Them. 'input' => 'text', 'select' => 'select-one', // Them => Us. 'text' => 'input', 'number' => 'input', 'date' => 'input', 'date_time' => 'input', 'select-one' => 'select', 'select-multi' => 'checkbox', ), ); return parent::get_data_keymap( $keymap ); } /** * {@inheritdoc} * * FluentCRM is self hosted and all the fields can be managed on the plugin itself. */ protected function _fetch_custom_fields( $list_id = '', $list = array() ) { static $processed = null; if ( is_null( $processed ) ) { // A. Default custom fields. $processed = array( 'address_line_1' => array( 'field_id' => 'address_line_1', 'name' => __( 'Address Line 1', 'et_builder' ), 'type' => 'input', 'hidden' => false, ), 'address_line_2' => array( 'field_id' => 'address_line_2', 'name' => __( 'Address Line 2', 'et_builder' ), 'type' => 'input', 'hidden' => false, ), 'postal_code' => array( 'field_id' => 'postal_code', 'name' => __( 'Postal Code', 'et_builder' ), 'type' => 'input', 'hidden' => false, ), 'city' => array( 'field_id' => 'city', 'name' => __( 'City', 'et_builder' ), 'type' => 'input', 'hidden' => false, ), 'state' => array( 'field_id' => 'state', 'name' => __( 'State', 'et_builder' ), 'type' => 'input', 'hidden' => false, ), 'country' => array( 'field_id' => 'country', 'name' => __( 'Country', 'et_builder' ), 'type' => 'input', 'hidden' => false, ), 'phone' => array( 'field_id' => 'phone', 'name' => __( 'Phone', 'et_builder' ), 'type' => 'input', 'hidden' => false, ), 'status' => array( 'field_id' => 'status', 'name' => __( 'Enable Double Optin', 'et_builder' ), 'type' => 'input', 'required_mark' => 'off', 'default' => 'pending', 'hidden' => true, ), ); // B. Contact custom fields. $contact_custom_fields = fluentcrm_get_option( 'contact_custom_fields', array() ); if ( ! empty( $contact_custom_fields ) ) { foreach ( $contact_custom_fields as $field ) { // 1. Transform field data to fit our format. $field = $this->transform_data_to_our_format( $field, 'custom_field' ); $field_id = $field['field_id']; $type = $field['type']; // 2. Transform field type to fit our supported field type. $field['type'] = self::$_->array_get( $this->data_keys, "custom_field_type.{$type}", 'any' ); if ( 'select-multi' === $type ) { $field['type_origin'] = $type; } // 3. Transform `options` data to fit our format (`id` => `name`). if ( ! empty( $field['options'] ) ) { $options = array(); foreach ( $field['options'] as $option ) { $option = array( 'value' => $option ); $option = $this->transform_data_to_our_format( $option, 'custom_field_option' ); $options[ $option['id'] ] = $option['name']; } $field['options'] = $options; } $processed[ $field_id ] = $field; } } } return $processed; } /** * {@inheritdoc} * * FluentCRM is self hosted and all the fields can be managed on the plugin itself. */ public function get_account_fields() { return array(); } /** * {@inheritdoc} * * FluentCRM is self hosted and all the lists can be managed on the plugin itself. */ public function fetch_subscriber_lists() { if ( ! defined( 'FLUENTCRM' ) ) { return self::$PLUGIN_REQUIRED; // phpcs:ignore ET.Sniffs.ValidVariableName.UsedPropertyNotSnakeCase -- Widely used on all email provider classes. } $list_tags = array(); // Lists. $lists = FluentCrmApi( 'lists' )->all(); foreach ( $lists as $list ) { $list_tags[ 'list_' . $list->id ] = array( 'list_id' => 'list_' . $list->id, 'name' => 'List: ' . $list->title, 'subscribers_count' => 0, ); } // Tags. $tags = FluentCrmApi( 'tags' )->all(); foreach ( $tags as $tag ) { $list_tags[ 'tags_' . $tag->id ] = array( 'list_id' => 'tags_' . $tag->id, 'name' => 'Tag: ' . $tag->title, 'subscribers_count' => 0, ); } // Combine both of lists and tags because there is no other way to display both // with different fields. $this->data['lists'] = $list_tags; $this->data['custom_fields'] = $this->_fetch_custom_fields( '', array() ); $this->data['is_authorized'] = true; $this->save_data(); return 'success'; } /** * {@inheritdoc} */ protected function _process_custom_fields( $args ) { if ( ! empty( $args['custom_fields'] ) ) { $custom_fields = $args['custom_fields']; foreach ( $custom_fields as $field_id => $field_value ) { if ( $field_value ) { $field_type = self::$_->array_get( $this->data['custom_fields'][ $field_id ], 'type' ); $field_type_origin = self::$_->array_get( $this->data['custom_fields'][ $field_id ], 'type_origin' ); // Transform `checkbox` value into string separated by comma i.e. 'val1,val2'. // However, if the field type origin is `select-multi`, we have to use array // values instead. if ( 'checkbox' === $field_type ) { $field_value = 'select-multi' === $field_type_origin ? array_values( $field_value ) : implode( ',', $field_value ); } $args[ $field_id ] = $field_value; } } if ( isset( $custom_fields['status'] ) ) { $args['status'] = 'pending'; } unset( $args['custom_fields'] ); } return $args; } /** * {@inheritdoc} */ public function subscribe( $args, $url = '' ) { if ( ! defined( 'FLUENTCRM' ) ) { ET_Core_Logger::error( self::$PLUGIN_REQUIRED ); // phpcs:ignore ET.Sniffs.ValidVariableName.UsedPropertyNotSnakeCase -- Widely used on all email provider classes. return esc_html__( 'An error occurred. Please try again later.', 'et_core' ); } $contact = $this->transform_data_to_provider_format( $args, 'subscriber' ); $contact = $this->_process_custom_fields( $contact ); // IP Address. $ip_address = 'true' === self::$_->array_get( $args, 'ip_address', 'true' ) ? et_core_get_ip_address() : ''; $contact['ip_address'] = $ip_address; // Name. if ( empty( $contact['last_name'] ) ) { $contact['full_name'] = $contact['first_name']; unset( $contact['first_name'] ); unset( $contact['last_name'] ); } // List or Tag. $list_or_tag_id = $args['list_id']; if ( false === strpos( $list_or_tag_id, 'tags_' ) ) { $contact['lists'] = array( intval( str_replace( 'list_', '', $list_or_tag_id ) ) ); } else { $contact['tags'] = array( intval( str_replace( 'tags_', '', $list_or_tag_id ) ) ); } $contact = array_filter( $contact ); // Email. if ( empty( $contact['email'] ) || ! is_email( $contact['email'] ) ) { return esc_html__( 'Email Validation has been failed.', 'et_core' ); } FluentCrmApi( 'contacts' )->createOrUpdate( $contact ); return 'success'; } } email/Feedblitz.php000064400000010115152214676150010263 0ustar00 $value ) { if ( is_array( $value ) && $value ) { // This is a multiple choice field (eg. checkbox, radio, select) $value = array_values( $value ); if ( count( $value ) > 1 ) { $value = implode( ',', $value ); } else { $value = array_pop( $value ); } } self::$_->array_set( $args, $field_id, rawurlencode( $value ) ); } return $args; } /** * @inheritDoc */ public function get_account_fields() { return array( 'api_key' => array( 'label' => esc_html__( 'API Key', 'et_core' ), ), ); } /** * @inheritDoc */ public function get_data_keymap( $keymap = array() ) { $keymap = array( 'list' => array( 'list_id' => 'id', 'name' => 'name', 'subscribers_count' => 'subscribersummary.subscribers', ), 'subscriber' => array( 'list_id' => 'listid', 'email' => 'email', 'name' => 'FirstName', 'last_name' => 'LastName', 'custom_fields' => 'custom_fields', ), 'error' => array( 'error_message' => 'rsp.err.@attributes.msg', ) ); return parent::get_data_keymap( $keymap ); } /** * @inheritDoc */ public function fetch_subscriber_lists() { if ( empty( $this->data['api_key'] ) ) { return $this->API_KEY_REQUIRED; } $this->http->expects_json = false; $this->response_data_key = false; $this->LISTS_URL = add_query_arg( 'key', $this->data['api_key'], $this->LISTS_URL ); parent::fetch_subscriber_lists(); $response = $this->data_utils->process_xmlrpc_response( $this->response->DATA, true ); $response = $this->data_utils->xml_to_array( $response ); if ( $this->response->ERROR || ! empty( $response['rsp']['err']['@attributes']['msg'] ) ) { return $this->get_error_message(); } $this->data['lists'] = $this->_process_subscriber_lists( $response['syndications']['syndication'] ); $this->data['is_authorized'] = true; $this->save_data(); return 'success'; } /** * @inheritDoc */ public function subscribe( $args, $url = '' ) { $query_args = array( 'email' => rawurlencode( $args['email'] ), 'name' => empty( $args['name'] ) ? '' : rawurlencode( $args['name'] ), 'last_name' => empty( $args['last_name'] ) ? '' : rawurlencode( $args['last_name'] ), 'custom_fields' => $args['custom_fields'], 'list_id' => $args['list_id'], ); $query = $this->transform_data_to_provider_format( $query_args, 'subscriber' ); $query = $this->_process_custom_fields( $query ); $query['key'] = rawurlencode( $this->data['api_key'] ); $url = add_query_arg( $query, "{$this->SUBSCRIBE_URL}?SimpleApiSubscribe" ); $this->prepare_request( $url, 'GET', false, null, false, false ); $this->make_remote_request(); $response = $this->data_utils->process_xmlrpc_response( $this->response->DATA, true ); $response = $this->data_utils->xml_to_array( $response ); if ( $this->response->ERROR || ! empty( $response['rsp']['err']['@attributes']['msg'] ) ) { return $this->get_error_message(); } if ( ! empty( $response['rsp']['success']['@attributes']['msg'] ) ) { return $response['rsp']['success']['@attributes']['msg']; } return 'success'; } } email/SalesForce.php000064400000027051152214676150010410 0ustar00REDIRECT_URL = add_query_arg( 'et-core-api-email-auth', 1, home_url( '', 'https' ) ); // @phpcs:ignore ET.Sniffs.ValidVariableName.UsedPropertyNotSnakeCase -- No need to change prop name. } else { $this->REDIRECT_URL = admin_url( 'admin.php?page=et_bloom_options', 'https' ); // @phpcs:ignore ET.Sniffs.ValidVariableName.UsedPropertyNotSnakeCase -- No need to change prop name. } $this->_set_base_url(); } protected function _fetch_custom_fields( $list_id = '', $list = array() ) { static $fields = null; $this->response_data_key = 'fields'; $this->prepare_request( "{$this->BASE_URL}/services/data/v39.0/sobjects/Lead/describe" ); if ( is_null( $fields ) ) { $fields = parent::_fetch_custom_fields( $list_id, $list ); foreach ( $fields as $index => $field ) { if ( ! isset( $field['custom'] ) || ! $field['custom'] ) { unset( $fields[ $index ] ); } } } return $fields; } /** * @return string */ protected function _fetch_subscriber_lists() { $query = urlencode( 'SELECT Id, Name, NumberOfLeads from Campaign LIMIT 100' ); $url = "{$this->BASE_URL}/services/data/v39.0/query?q={$query}"; $this->response_data_key = 'records'; $this->prepare_request( $url ); return parent::fetch_subscriber_lists(); } protected function _process_custom_fields( $args ) { if ( ! isset( $args['custom_fields'] ) ) { return $args; } $fields = $args['custom_fields']; unset( $args['custom_fields'] ); foreach ( $fields as $field_id => $value ) { if ( is_array( $value ) && $value ) { // This is a multiple choice field (eg. checkbox, radio, select) $value = array_values( $value ); if ( 'checkbox' === $this->data['custom_fields'][ $field_id ]['type'] ) { $value = implode( ';', $value ); } else { $value = array_pop( $value ); } } self::$_->array_set( $args, "custom_fields.{$field_id}", $value ); } return $args; } public function _set_base_url() { // If we already have the `instance_url`, use it as the base API url. if ( isset( $this->data['instance_url'] ) && ! empty( $this->data['instance_url'] ) ) { $this->BASE_URL = untrailingslashit( $this->data['instance_url'] ); // @phpcs:ignore ET.Sniffs.ValidVariableName.UsedPropertyNotSnakeCase -- No need to change prop name. } else { $this->BASE_URL = empty( $this->data['login_url'] ) ? '' : untrailingslashit( $this->data['login_url'] ); // @phpcs:ignore ET.Sniffs.ValidVariableName.UsedPropertyNotSnakeCase -- No need to change prop name. } } public function authenticate() { $this->data['consumer_secret'] = $this->data['client_secret']; $this->data['consumer_key'] = $this->data['api_key']; return parent::authenticate(); } /** * @inheritDoc */ public function get_account_fields() { return array( // SalesForce supports OAuth for SSL websites so generate different fields in this case 'login_url' => array( 'label' => esc_html__( 'Instance URL', 'et_core' ), 'required' => 'https', 'show_if' => array( 'function.protocol' => 'https' ), ), 'api_key' => array( 'label' => esc_html__( 'Consumer Key', 'et_core' ), 'required' => 'https', 'show_if' => array( 'function.protocol' => 'https' ), ), 'client_secret' => array( 'label' => esc_html__( 'Consumer Secret', 'et_core' ), 'required' => 'https', 'show_if' => array( 'function.protocol' => 'https' ), ), // This has to be the last field because is the only one shown in both cases and // CANCEL / SUBMIT buttons will be attached to it. 'organization_id' => array( 'label' => esc_html__( 'Organization ID', 'et_core' ), 'required' => 'http', ), ); } /** * @inheritDoc */ public function fetch_subscriber_lists() { $this->_set_base_url(); // SalesForce supports 2 types of authentication: Simple and OAuth2 if ( isset( $this->data['api_key'], $this->data['client_secret'] ) && ! empty( $this->data['api_key'] ) && ! empty( $this->data['client_secret'] ) ) { // Fetch lists if user already authenticated. if ( $this->is_authenticated() ) { return $this->_fetch_subscriber_lists(); } $authenticated = $this->authenticate(); // If the authenticating process returns an array with redirect url to complete OAuth authorization. if ( is_array( $authenticated ) ) { return $authenticated; } if ( true === $authenticated ) { // Need to reinitialize the OAuthHelper with the new data, to set the authorization header in the next request. $urls = array( 'access_token_url' => $this->ACCESS_TOKEN_URL, // @phpcs:ignore -- No need to change the class property 'request_token_url' => $this->REQUEST_TOKEN_URL, // @phpcs:ignore -- No need to change the class property 'authorization_url' => $this->AUTHORIZATION_URL, // @phpcs:ignore -- No need to change the class property 'redirect_url' => $this->REDIRECT_URL, // @phpcs:ignore -- No need to change the class property ); $this->OAuth_Helper = new ET_Core_API_OAuthHelper( $this->data, $urls, $this->owner ); // @phpcs:ignore ET.Sniffs.ValidVariableName.UsedPropertyNotSnakeCase -- No need to change the prop name. return $this->_fetch_subscriber_lists(); } return false; } elseif ( isset( $this->data['organization_id'] ) && '' !== $this->data['organization_id'] ) { // Simple $this->data['is_authorized'] = 'true'; $this->data['lists'] = array( array( 'list_id' => 0, 'name' => 'WebToLead', 'subscribers_count' => 0 ) ); $this->save_data(); // return 'success' immediately in case of simple authentication. Lists cannot be retrieved with this type. return 'success'; } else { return esc_html__( 'Organization ID cannot be empty', 'et_core' ); } } /** * @inheritDoc */ public function get_data_keymap( $keymap = array() ) { $keymap = array( 'list' => array( 'list_id' => 'Id', 'name' => 'Name', 'subscribers_count' => 'NumberOfLeads', ), 'subscriber' => array( 'name' => 'FirstName', 'last_name' => 'LastName', 'email' => 'Email', 'custom_fields' => 'custom_fields', ), 'custom_field' => array( 'field_id' => 'name', 'name' => 'label', 'type' => 'type', 'options' => 'valueSet', ), 'custom_field_type' => array( // Us => Them 'input' => 'Text', 'textarea' => 'TextArea', 'checkbox' => 'MultiselectPicklist', 'select' => 'Picklist', // Them => Us 'Text' => 'input', 'TextArea' => 'textarea', 'MultiselectPicklist' => 'checkbox', 'Picklist' => 'select', ), ); return parent::get_data_keymap( $keymap ); } public function get_subscriber( $email ) { $query = urlencode( "SELECT Id from Lead where Email='{$email}' LIMIT 100" ); $url = "{$this->BASE_URL}/services/data/v39.0/query?q={$query}"; $this->response_data_key = 'records'; $this->prepare_request( $url ); $this->make_remote_request(); $response = $this->response; if ( $response->ERROR || empty( $response->DATA['records'] ) ) { return false; } return isset( $response->DATA['records'][0]['Id'] ) ? $response->DATA['records'][0]['Id'] : false; } /** * @inheritDoc */ public function subscribe( $args, $url = '' ) { if ( empty( $this->data['access_secret'] ) ) { // Try to use simple web form return $this->subscribe_salesforce_web( $args ); } $error_message = esc_html__( 'An error occurred. Please try again.', 'et_core' ); $subscriber_id = $this->get_subscriber( $args['email'] ); if ( ! $subscriber_id ) { $url = "{$this->BASE_URL}/services/data/v39.0/sobjects/Lead"; $content = $this->transform_data_to_provider_format( $args, 'subscriber' ); $content = $this->_process_custom_fields( $content ); $content['Company'] = 'Bloom'; if ( isset( $content['custom_fields'] ) && is_array( $content['custom_fields'] ) ) { $content = array_merge( $content, $content['custom_fields'] ); unset( $content['custom_fields'] ); } // The LastName is required by Salesforce, whereas it is possible for Optin Form to not have the last name field. if ( ! isset( $content['LastName'] ) || empty( $content['LastName'] ) ) { $content['LastName'] = '[not provided]'; } $this->prepare_request( $url, 'POST', false, json_encode( $content ), true ); $this->response_data_key = false; $result = parent::subscribe( $content, $url ); if ( 'success' !== $result || empty( $this->response->DATA['id'] ) ) { return $error_message; } $subscriber_id = $this->response->DATA['id']; } $url = "{$this->BASE_URL}/services/data/v39.0/sobjects/CampaignMember"; $content = array( 'LeadId' => $subscriber_id, 'CampaignId' => $args['list_id'], ); $this->prepare_request( $url, 'POST', false, json_encode( $content ), true ); $result = parent::subscribe( $content, $url ); if ( 'success' !== $result && ! empty( $this->response->DATA['errors'] ) ) { return $this->response->DATA['errors'][0]; } else if ( 'success' !== $result ) { return $error_message; } return 'success'; } /** * Post web-to-lead request to SalesForce * * @return string */ public function subscribe_salesforce_web( $args ) { if ( ! isset( $this->data['organization_id'] ) || '' === $this->data['organization_id'] ) { return esc_html__( 'Unknown Organization ID', 'et_core' ); } // Define SalesForce web-to-lead endpoint $url = 'https://webto.salesforce.com/servlet/servlet.WebToLead?encoding=UTF-8'; $args = $this->transform_data_to_provider_format( $args, 'subscriber' ); $args = $this->_process_custom_fields( $args ); // Prepare arguments for web-to-lead POST $form_args = array( 'body' => array( 'oid' => sanitize_text_field( $this->data['organization_id'] ), 'retURL' => esc_url( home_url( '/' ) ), 'email' => sanitize_email( $args['Email'] ), ), ); if ( '' !== $args['FirstName'] ) { $form_args['body']['first_name'] = sanitize_text_field( $args['FirstName'] ); } if ( '' !== $args['LastName'] ) { $form_args['body']['last_name'] = sanitize_text_field( $args['LastName'] ); } if ( isset( $args['custom_fields'] ) && is_array( $args['custom_fields'] ) ) { $form_args = array_merge( $form_args, $args['custom_fields'] ); } // Post to SalesForce web-to-lead endpoint $request = wp_remote_post( $url, $form_args ); if ( ! is_wp_error( $request ) && 200 === wp_remote_retrieve_response_code( $request ) ) { return 'success'; } return esc_html__( 'An error occurred. Please try again.', 'et_core' ); } } email/init.php000064400000007425152214676150007330 0ustar00accounts(); foreach ( $all_accounts as $provider_slug => $accounts ) { $provider = $providers->get( $provider_slug, '' ); foreach ( $accounts as $account ) { $provider->set_account_name( $account ); $provider->fetch_subscriber_lists(); } } } endif; if ( ! function_exists( 'et_core_api_email_fetch_lists' ) ): /** * Fetch the latest email lists for a provider account and update the database accordingly. * * @param string $name_or_slug The provider name or slug. * @param string $account The account name. * @param string $api_key Optional. The api key (if fetch succeeds, the key will be saved). * * @return string 'success' if successful, an error message otherwise. */ function et_core_api_email_fetch_lists( $name_or_slug, $account, $api_key = '' ) { if ( ! empty( $api_key ) ) { // The account provided either doesn't exist yet or has a new api key. et_core_security_check( 'manage_options' ); } if ( empty( $name_or_slug ) || empty( $account ) ) { return __( 'ERROR: Invalid arguments.', 'et_core' ); } $providers = ET_Core_API_Email_Providers::instance(); $provider = $providers->get( $name_or_slug, $account, 'builder' ); if ( ! $provider ) { return ''; } if ( is_array( $api_key ) ) { foreach ( $api_key as $field_name => $value ) { $provider->data[ $field_name ] = sanitize_text_field( $value ); } } else if ( '' !== $api_key ) { $provider->data['api_key'] = sanitize_text_field( $api_key ); } return $provider->fetch_subscriber_lists(); } endif; if ( ! function_exists( 'et_core_api_email_providers' ) ): /** * @deprecated {@see ET_Core_API_Email_Providers::instance()} * * @return ET_Core_API_Email_Providers */ function et_core_api_email_providers() { return ET_Core_API_Email_Providers::instance(); } endif; if ( ! function_exists( 'et_core_api_email_remove_account' ) ): /** * Delete an existing provider account. * * @param string $name_or_slug The provider name or slug. * @param string $account The account name. */ function et_core_api_email_remove_account( $name_or_slug, $account ) { et_core_security_check( 'manage_options' ); if ( empty( $name_or_slug ) || empty( $account ) ) { return; } // If the account being removed is a legacy account (pre-dates core api), remove the old data. switch( $account ) { case 'Divi Builder Aweber': et_delete_option( 'divi_aweber_consumer_key' ); et_delete_option( 'divi_aweber_consumer_secret' ); et_delete_option( 'divi_aweber_access_key' ); et_delete_option( 'divi_aweber_access_secret' ); break; case 'Divi Builder Plugin Aweber': $opts = (array) get_option( 'et_pb_builder_options' ); unset( $opts['aweber_consumer_key'], $opts['aweber_consumer_secret'], $opts['aweber_access_key'], $opts['aweber_access_secret'] ); update_option( 'et_pb_builder_options', $opts ); break; case 'Divi Builder MailChimp': et_delete_option( 'divi_mailchimp_api_key' ); break; case 'Divi Builder Plugin MailChimp': $options = (array) get_option( 'et_pb_builder_options' ); unset( $options['newsletter_main_mailchimp_key'] ); update_option( 'et_pb_builder_options', $options ); break; } $providers = ET_Core_API_Email_Providers::instance(); $provider = $providers->get( $name_or_slug, $account ); if ( $provider ) { $provider->delete(); } } endif; email/Fields.php000064400000037122152214676150007570 0ustar00names_by_slug( 'all', 'custom_fields' ) ); $custom_fields_data = self::$_providers->custom_fields_data(); $fields = array(); if ( 'bloom' === self::$owner ) { $fields = array( 'use_custom_fields' => array( 'label' => esc_html__( 'Use Custom Fields', 'et_core' ), 'type' => 'yes_no_button', 'options' => array( 'on' => esc_html__( 'Yes', 'et_core' ), 'off' => esc_html__( 'No', 'et_core' ), ), 'default' => 'off', 'show_if' => array( 'email_provider' => $custom_fields_support, ), 'allow_dynamic' => array_keys( self::$_providers->names_by_slug( 'all', 'dynamic_custom_fields' ) ), 'description' => esc_html__( 'Enable this option to use custom fields in your opt-in form.', 'et_core' ), ), 'custom_fields' => array( 'type' => 'sortable_list', 'label' => '', 'default' => '[]', ), 'editing_field' => array( 'type' => 'skip', 'default' => 'off', ), ); } foreach ( $custom_fields_data as $provider => $accounts ) { foreach ( $accounts as $account => $lists ) { $account_name = str_replace( ' ', '', strtolower( $account ) ); $key = "predefined_field_{$provider}_{$account_name}"; if ( isset( $lists['custom_fields'] ) ) { // Custom fields are per account $fields[ $key ] = self::_predefined_custom_field_select( $lists['custom_fields'], $provider, $account ); continue; } foreach ( $lists as $list_id => $custom_fields ) { // Custom fields are per list $key = "predefined_field_{$provider}_{$account_name}_{$list_id}"; $fields[ $key ] = self::_predefined_custom_field_select( $custom_fields, $provider, $account, $list_id ); } } } $labels = array( 'link_url' => esc_html__( 'Link URL', 'et_core' ), 'link_text' => esc_html__( 'Link Text', 'et_core' ), 'link_cancel' => esc_html__( 'Discard Changes', 'et_core' ), 'link_save' => esc_html__( 'Save Changes', 'et_core' ), 'link_settings' => esc_html__( 'Option Link', 'et_core' ), ); $fields = array_merge( $fields, array( 'predefined_field' => array( 'type' => 'skip', 'default' => 'none', ), 'field_id' => array( 'label' => esc_html__( 'ID', 'et_core' ), 'type' => 'text', 'default' => '', // <--- Intentional 'description' => esc_html__( 'Define a unique ID for this field. You should use only English characters without special characters or spaces.', 'et_core' ), 'toggle_slug' => 'main_content', 'readonly_if' => array( $readonly_dependency => self::$_predefined_custom_field_support, ), ), 'field_title' => array( 'label' => esc_html__( 'Name', 'et_core' ), 'type' => 'text', 'description' => esc_html__( 'Set the label that will appear above this field in the opt-in form.', 'et_core' ), 'toggle_slug' => 'main_content', 'readonly_if' => array( $readonly_dependency => self::$_predefined_custom_field_support, ), 'readonly_if_not' => array( $readonly_dependency => array( 'getresponse', 'sendinblue', 'constant_contact', 'fluentcrm' ), ), ), 'field_type' => array( 'label' => esc_html__( 'Type', 'et_core' ), 'type' => 'select', 'default' => 'none', 'option_category' => 'basic_option', 'options' => array( 'none' => esc_html__( 'Choose a field type...', 'et_core' ), 'input' => esc_html__( 'Input Field', 'et_core' ), 'email' => esc_html__( 'Email Field', 'et_core' ), 'text' => esc_html__( 'Textarea', 'et_core' ), 'checkbox' => esc_html__( 'Checkboxes', 'et_core' ), 'radio' => esc_html__( 'Radio Buttons', 'et_core' ), 'select' => esc_html__( 'Select Dropdown', 'et_core' ), ), 'description' => esc_html__( 'Choose the type of field', 'et_core' ), 'toggle_slug' => 'field_options', 'readonly_if' => array( $readonly_dependency => self::$_predefined_custom_field_support, ), 'readonly_if_not' => array( $readonly_dependency => self::$_any_custom_field_type_support, ), ), 'checkbox_checked' => array( 'label' => esc_html__( 'Checked By Default', 'et_core' ), 'description' => esc_html__( 'If enabled, the check mark will be automatically selected for the visitor. They can still deselect it.', 'et_core' ), 'type' => 'hidden', 'option_category' => 'layout', 'default' => 'off', 'toggle_slug' => 'field_options', 'show_if' => array( 'field_type' => 'checkbox', ), ), 'checkbox_options' => array( 'label' => esc_html__( 'Options', 'et_core' ), 'type' => 'sortable_list', 'checkbox' => true, 'option_category' => 'basic_option', 'toggle_slug' => 'field_options', 'readonly_if' => array( $readonly_dependency => self::$_predefined_custom_field_support, ), 'readonly_if_not' => array( $readonly_dependency => self::$_any_custom_field_type_support, ), 'show_if' => array( 'field_type' => 'checkbox', ), 'right_actions' => 'move|link|copy|delete', 'right_actions_readonly' => 'move|link', 'labels' => $labels, ), 'radio_options' => array( 'label' => esc_html__( 'Options', 'et_core' ), 'type' => 'sortable_list', 'radio' => true, 'option_category' => 'basic_option', 'toggle_slug' => 'field_options', 'readonly_if' => array( $readonly_dependency => self::$_predefined_custom_field_support, ), 'readonly_if_not' => array( $readonly_dependency => self::$_any_custom_field_type_support, ), 'show_if' => array( 'field_type' => 'radio', ), 'right_actions' => 'move|link|copy|delete', 'right_actions_readonly' => 'move|link', 'labels' => $labels, ), 'select_options' => array( 'label' => esc_html__( 'Options', 'et_core' ), 'type' => 'sortable_list', 'option_category' => 'basic_option', 'toggle_slug' => 'field_options', 'readonly_if' => array( $readonly_dependency => self::$_predefined_custom_field_support, ), 'readonly_if_not' => array( $readonly_dependency => self::$_any_custom_field_type_support, ), 'show_if' => array( 'field_type' => 'select', ), 'right_actions' => 'move|copy|delete', 'right_actions_readonly' => 'move', ), 'min_length' => array( 'label' => esc_html__( 'Minimum Length', 'et_core' ), 'description' => esc_html__( 'Leave at 0 to remove restriction', 'et_core' ), 'type' => 'range', 'default' => '0', 'unitless' => true, 'range_settings' => array( 'min' => '0', 'max' => '255', 'step' => '1', ), 'option_category' => 'basic_option', 'toggle_slug' => 'field_options', 'show_if' => array( 'field_type' => 'input', ), ), 'max_length' => array( 'label' => esc_html__( 'Maximum Length', 'et_core' ), 'description' => esc_html__( 'Leave at 0 to remove restriction', 'et_core' ), 'type' => 'range', 'default' => '0', 'unitless' => true, 'range_settings' => array( 'min' => '0', 'max' => '255', 'step' => '1', ), 'option_category' => 'basic_option', 'toggle_slug' => 'field_options', 'show_if' => array( 'field_type' => 'input', ), ), 'allowed_symbols' => array( 'label' => esc_html__( 'Allowed Symbols', 'et_core' ), 'description' => esc_html__( 'You can validate certain types of information by disallowing certain symbols. Symbols added here will prevent the form from being submitted if added by the user.', 'et_core' ), 'type' => 'select', 'default' => 'all', 'options' => array( 'all' => esc_html__( 'All', 'et_core' ), 'letters' => esc_html__( 'Letters Only (A-Z)', 'et_core' ), 'numbers' => esc_html__( 'Numbers Only (0-9)', 'et_core' ), 'alphanumeric' => esc_html__( 'Alphanumeric Only (A-Z, 0-9)', 'et_core' ), ), 'option_category' => 'basic_option', 'toggle_slug' => 'field_options', 'show_if' => array( 'field_type' => 'input', ), ), 'required_mark' => array( 'label' => esc_html__( 'Required Field', 'et_core' ), 'type' => 'yes_no_button', 'option_category' => 'configuration', 'default' => 'on', 'options' => array( 'on' => esc_html__( 'Yes', 'et_core' ), 'off' => esc_html__( 'No', 'et_core' ), ), 'description' => esc_html__( 'Define whether the field should be required or optional', 'et_core' ), 'toggle_slug' => 'field_options', 'show_if_not' => array( 'email_provider' => 'getresponse', ), ), 'hidden' => array( 'label' => esc_html__( 'Hidden Field', 'et_core' ), 'type' => 'yes_no_button', 'option_category' => 'configuration', 'default' => 'off', 'options' => array( 'on' => esc_html__( 'Yes', 'et_core' ), 'off' => esc_html__( 'No', 'et_core' ), ), 'description' => esc_html__( 'Define whether or not the field should be visible.', 'et_core' ), 'toggle_slug' => 'field_options', 'readonly_if' => array( $readonly_dependency => self::$_predefined_custom_field_support, ), 'readonly_if_not' => array( $readonly_dependency => self::$_any_custom_field_type_support, ), ), 'fullwidth_field' => array( 'label' => esc_html__( 'Make Fullwidth', 'et_core' ), 'type' => 'yes_no_button', 'option_category' => 'layout', 'options' => array( 'on' => esc_html__( 'Yes', 'et_core' ), 'off' => esc_html__( 'No', 'et_core' ), ), 'tab_slug' => 'advanced', 'toggle_slug' => 'layout', 'description' => esc_html__( 'If enabled, the field will take 100% of the width of the form, otherwise it will take 50%', 'et_core' ), 'default' => array( 'parent:layout', array( 'left_right' => 'on', 'right_left' => 'on', 'top_bottom' => 'off', 'bottom_top' => 'off', )), ), ) ); if ( 'builder' === self::$owner ) { $fields = array_merge( $fields, array( 'field_background_color' => array( 'label' => esc_html__( 'Field Background Color', 'et_core' ), 'description' => esc_html__( "Pick a color to fill the module's input fields.", 'et_core' ), 'type' => 'color-alpha', 'custom_color' => true, 'toggle_slug' => 'form_field', 'tab_slug' => 'advanced', ), 'conditional_logic' => array( 'label' => esc_html__( 'Enable', 'et_core' ), 'type' => 'yes_no_button', 'option_category' => 'layout', 'default' => 'off', 'options' => array( 'on' => esc_html__( 'Yes', 'et_core' ), 'off' => esc_html__( 'No', 'et_core' ), ), 'description' => et_get_safe_localization( __( "Enabling conditional logic makes this field only visible when any or all of the rules below are fulfilled
Note: Only fields with an unique and non-empty field ID can be used", 'et_core' ) ), 'toggle_slug' => 'conditional_logic', ), 'conditional_logic_relation' => array( 'label' => esc_html__( 'Relation', 'et_core' ), 'type' => 'yes_no_button', 'option_category' => 'layout', 'options' => array( 'on' => esc_html__( 'All', 'et_core' ), 'off' => esc_html__( 'Any', 'et_core' ), ), 'default' => 'off', 'button_options' => array( 'button_type' => 'equal', ), 'description' => esc_html__( 'Choose whether any or all of the rules should be fulfilled', 'et_core' ), 'toggle_slug' => 'conditional_logic', 'show_if' => array( 'conditional_logic' => 'on', ), ), 'conditional_logic_rules' => array( 'label' => esc_html__( 'Rules', 'et_core' ), 'description' => esc_html__( 'Conditional logic rules can be used to hide and display different input fields conditionally based on how the visitor has interacted with different inputs.', 'et_core' ), 'type' => 'conditional_logic', 'option_category' => 'layout', 'depends_show_if' => 'on', 'toggle_slug' => 'conditional_logic', 'show_if' => array( 'conditional_logic' => 'on', ), ), ) ); } if ( 'bloom' === self::$owner ) { foreach ( $fields as $field_slug => &$field ) { if ( 'use_custom_fields' !== $field_slug ) { self::$_->array_set( $field, 'show_if.use_custom_fields', 'on' ); } } } return $fields; } protected static function _predefined_custom_field_select( $custom_fields, $provider, $account_name, $list_id = '' ) { $is_builder = 'builder' === self::$owner; $is_bloom = 'bloom' === self::$owner; $dependency = $is_builder ? 'parentModule:provider' : 'email_provider'; $show_if = array( $dependency => $provider, ); if ( $is_bloom ) { $show_if['account_name'] = $account_name; } if ( $list_id && $is_builder ) { $dependency = "parentModule:{$provider}_list"; $show_if[ $dependency ] = "{$account_name}|{$list_id}"; } else if ( $list_id && $is_bloom ) { $show_if['email_list'] = (string) $list_id; } $options = array( 'none' => esc_html__( 'Choose a field...', 'et_core' ) ); foreach ( $custom_fields as $field ) { $field_id = isset( $field['group_id'] ) ? $field['group_id'] : $field['field_id']; $options[ $field_id ] = $field['name']; } return array( 'label' => esc_html__( 'Field', 'et_core' ), 'type' => 'select', 'options' => $options, 'order' => array_keys( $options ), 'show_if' => $show_if, 'toggle_slug' => 'main_content', 'default' => 'none', 'description' => esc_html__( 'Choose a custom field. Custom fields must be defined in your email provider account.', 'et_core' ), ); } /** * Get field definitions * * @since 3.10 * * @param string $type Accepts 'custom_field' * @param string $for Accepts 'builder', 'bloom' * * @return array */ public static function get_definitions( $for, $type = 'custom_field' ) { self::$owner = $for; $fields = array(); if ( 'custom_field' === $type ) { $fields = self::_custom_field_definitions(); } return $fields; } public static function initialize() { self::$_ = ET_Core_Data_Utils::instance(); self::$_providers = ET_Core_API_Email_Providers::instance(); self::$_predefined_custom_field_support = array_keys( self::$_providers->names_by_slug( 'all', 'predefined_custom_fields' ) ); self::$_any_custom_field_type_support = self::$_providers->names_by_slug( 'all', 'any_custom_field_type' ); } } ET_Core_API_Email_Fields::initialize(); email/MailChimp.php000064400000022672152214676150010231 0ustar00 '-', 'password' => 'api_key', ); /** * @inheritDoc */ public $name = 'MailChimp'; /** * @inheritDoc */ public $slug = 'mailchimp'; public function __construct( $owner, $account_name, $api_key = '' ) { parent::__construct( $owner, $account_name, $api_key ); if ( ! empty( $this->data['api_key'] ) ) { $this->_set_base_url(); } $this->http_auth['username'] = $owner; } protected function _add_note_to_subscriber( $email, $url ) { $email = md5( $email ); $this->prepare_request( "{$url}/$email/notes", 'POST' ); $this->request->BODY = json_encode( array( 'note' => $this->SUBSCRIBED_VIA ) ); $this->make_remote_request(); } protected function _fetch_custom_fields( $list_id = '', $list = array() ) { $this->response_data_key = 'merge_fields'; $this->prepare_request( "{$this->BASE_URL}/lists/{$list_id}/merge-fields?count={$this->COUNT}" ); $fields = parent::_fetch_custom_fields( $list_id, $list ); foreach ( $fields as $id => $field ) { if ( in_array( $id, array( 1, 2 ) ) ) { unset( $fields[ $id ] ); } } // MailChimp is weird in that they treat checkbox fields as an entirely different concept in their API (Groups) // We'll grab the groups and treat them as checkbox fields in our UI. $groups = $this->_fetch_subscriber_list_groups( $list_id ); return $fields + $groups; } protected function _fetch_subscriber_list_group_options( $list_id, $group_id ) { $this->prepare_request( "{$this->BASE_URL}/lists/{$list_id}/interest-categories/{$group_id}/interests?count={$this->COUNT}" ); $this->make_remote_request(); if ( $this->response->ERROR ) { et_debug( $this->get_error_message() ); return array(); } $data = $this->response->DATA['interests']; $options = array(); foreach ( $data as $option ) { $option = $this->transform_data_to_our_format( $option, 'group_option' ); $id = $option['id']; $options[ $id ] = $option['name']; } return $options; } protected function _fetch_subscriber_list_groups( $list_id ) { $this->response_data_key = 'categories'; $this->prepare_request( "{$this->BASE_URL}/lists/{$list_id}/interest-categories?count={$this->COUNT}" ); $this->make_remote_request(); $groups = array(); if ( false !== $this->response_data_key && empty( $this->response_data_key ) ) { // Let child class handle parsing the response data themselves. return $groups; } if ( $this->response->ERROR ) { et_debug( $this->get_error_message() ); return $groups; } $data = $this->response->DATA[ $this->response_data_key ]; foreach ( $data as $group ) { $group = $this->transform_data_to_our_format( $group, 'group' ); $field_id = $group['field_id']; $type = $group['type']; if ( 'hidden' === $type ) { // MailChimp only allows groups of type: 'checkbox' to be hidden. $group['type'] = 'checkbox'; $group['hidden'] = true; } $group['is_group'] = true; $group['options'] = $this->_fetch_subscriber_list_group_options( $list_id, $field_id ); $group['type'] = self::$_->array_get( $this->data_keys, "custom_field_type.{$type}", 'text' ); $groups[ $field_id ] = $group; } return $groups; } protected function _process_custom_fields( $args ) { if ( ! isset( $args['custom_fields'] ) ) { return $args; } $fields = $args['custom_fields']; $list_id = self::$_->array_get( $args, 'list_id', '' ); unset( $args['custom_fields'] ); unset( $args['list_id'] ); $custom_fields_data = self::$_->array_get( $this->data, "lists.{$list_id}.custom_fields", array() ); foreach ( $fields as $field_id => $value ) { $is_group = self::$_->array_get( $custom_fields_data, "{$field_id}.is_group", false ); if ( is_array( $value ) && $value ) { foreach ( $value as $id => $field_value ) { if ( $is_group ) { // If it is a group custom field, set as `interests` and don't process the `merge_fields` self::$_->array_set( $args, "interests.{$id}", true ); $field_id = false; } else { $value = $field_value; } } } if ( false === $field_id ) { continue; } // In previous version of Mailchimp implementation we only supported default field tag, but it can be customized and our code fails. // Added `field_tag` attribute which is actual field tag. Fallback to default field tag if `field_tag` doesn't exist for backward compatibility. $custom_field_tag = self::$_->array_get( $custom_fields_data, "{$field_id}.field_tag", "MMERGE{$field_id}" ); // Need to strips existing slash chars. self::$_->array_set( $args, "merge_fields.{$custom_field_tag}", stripslashes( $value ) ); } return $args; } protected function _set_base_url() { $api_key_pieces = explode( '-', $this->data['api_key'] ); $datacenter = empty( $api_key_pieces[1] ) ? '' : $api_key_pieces[1]; $this->BASE_URL = str_replace( '@datacenter@', $datacenter, $this->BASE_URL_PATTERN ); } /** * @inheritDoc */ public function fetch_subscriber_lists() { if ( empty( $this->data['api_key'] ) ) { return $this->API_KEY_REQUIRED; } $this->_set_base_url(); /** * The maximum number of subscriber lists to request from MailChimp's API. * * @since 2.0.0 * * @param int $max_lists */ $max_lists = (int) apply_filters( 'et_core_api_email_mailchimp_max_lists', 250 ); $url = "{$this->BASE_URL}/lists?count={$max_lists}&fields=lists.name,lists.id,lists.stats,lists.double_optin"; $this->prepare_request( $url ); $this->response_data_key = 'lists'; $result = parent::fetch_subscriber_lists(); return $result; } /** * @inheritDoc */ public function get_account_fields() { return array( 'api_key' => array( 'label' => esc_html__( 'API Key', 'et_core' ), ), ); } /** * @inheritDoc */ public function get_data_keymap( $keymap = array() ) { $keymap = array( 'list' => array( 'list_id' => 'id', 'name' => 'name', 'double_optin' => 'double_optin', 'subscribers_count' => 'stats.member_count', ), 'subscriber' => array( 'email' => 'email_address', 'name' => 'merge_fields.FNAME', 'last_name' => 'merge_fields.LNAME', 'custom_fields' => 'custom_fields', ), 'error' => array( 'error_message' => 'detail', ), 'custom_field' => array( 'field_id' => 'merge_id', 'field_tag' => 'tag', 'name' => 'name', 'type' => 'type', 'hidden' => '!public', 'options' => 'options.choices', ), 'custom_field_type' => array( // Us <=> Them 'radio' => 'radio', // Us => Them 'input' => 'text', 'select' => 'dropdown', 'checkbox' => 'checkboxes', // Them => Us 'text' => 'input', 'dropdown' => 'select', 'checkboxes' => 'checkbox', ), 'group' => array( 'field_id' => 'id', 'name' => 'title', 'type' => 'type', ), 'group_option' => array( 'id' => 'id', 'name' => 'name', ), ); return parent::get_data_keymap( $keymap ); } public function get_subscriber( $list_id, $email ) { $hash = md5( strtolower( $email ) ); $this->prepare_request( implode( '/', array( $this->BASE_URL, 'lists', $list_id, 'members', $hash ) ) ); $this->make_remote_request(); return $this->response->STATUS_CODE !== 200 ? null : $this->response->DATA; } /** * @inheritDoc */ public function subscribe( $args, $url = '' ) { $list_id = $args['list_id']; $args = $this->transform_data_to_provider_format( $args, 'subscriber' ); $url = "{$this->BASE_URL}/lists/{$list_id}/members"; $email = $args['email_address']; $err = esc_html__( 'An error occurred, please try later.', 'et_core' ); $dbl_optin = self::$_->array_get( $this->data, "lists.{$list_id}.double_optin", true ); $ip_address = 'true' === self::$_->array_get( $args, 'ip_address', 'true' ) ? et_core_get_ip_address() : '0.0.0.0'; $args['ip_signup'] = $ip_address; $args['status'] = $dbl_optin ? 'pending' : 'subscribed'; $args['list_id'] = $list_id; $args = $this->_process_custom_fields( $args ); $this->prepare_request( $url, 'POST', false, $args, true ); $result = parent::subscribe( $args, $url ); if ( false !== stripos( $result, 'already a list member' ) ) { $result = $err; if ( $user = $this->get_subscriber( $list_id, $email ) ) { if ( 'subscribed' === $user['status'] ) { $result = 'success'; } else { $this->prepare_request( implode( '/', array( $url, $user['id'] ) ), 'PUT', false, $args, true ); $result = parent::subscribe( $args, $url ); } } } if ( 'success' === $result ) { $this->_add_note_to_subscriber( $email, $url ); } else if ( false !== stripos( $result, 'has signed up to a lot of lists ' ) ) { // return message which can be translated. Generic Mailchimp messages are not translatable. $result = esc_html__( 'You have signed up to a lot of lists very recently, please try again later', 'et_core' ); } else { $result = $err; } return $result; } } email/iContact.php000064400000015607152214676150010132 0ustar00prepare_request( $this->FIELDS_URL ); $this->make_remote_request(); $result = array(); if ( $this->response->ERROR ) { et_debug( $this->get_error_message() ); return $result; } $data = $this->response->DATA['customfields']; foreach ( $data as &$custom_field ) { $custom_field = $this->transform_data_to_our_format( $custom_field, 'custom_field' ); } $fields = array(); foreach ( $data as $field ) { if ( 'text' !== $field['type'] ) { continue; } $field_id = $field['field_id']; $type = self::$_->array_get( $field, 'type', 'any' ); $field['type'] = self::$_->array_get( $this->data_keys, "custom_field_type.{$type}", 'any' ); $fields[ $field_id ] = $field; } return $fields; } protected function _set_custom_headers() { if ( ! empty( $this->custom_headers ) ) { return; } $this->custom_headers = array( 'Accept' => 'application/json', 'API-Version' => '2.2', 'API-AppId' => sanitize_text_field( $this->data['client_id'] ), 'API-Username' => sanitize_text_field( $this->data['username'] ), 'API-Password' => sanitize_text_field( $this->data['password'] ), ); } protected function _get_account_id() { if ( ! empty( $this->data['account_id'] ) ) { return $this->data['account_id']; } $this->prepare_request( 'https://app.icontact.com/icp/a' ); $this->make_remote_request(); if ( isset( $this->response->DATA['accounts'][0]['accountId'] ) ) { $this->data['account_id'] = $this->response->DATA['accounts'][0]['accountId']; } return $this->data['account_id']; } protected function _get_subscriber( $args, $exclude = null ) { $default_excludes = array( 'name', 'last_name' ); if ( is_array( $exclude ) ) { $exclude = array_merge( $default_excludes, $exclude ); } else if ( $exclude ) { $default_excludes[] = $exclude; $exclude = $default_excludes; } $args = $this->transform_data_to_provider_format( $args, 'subscriber', $exclude ); $url = add_query_arg( $args, $this->SUBSCRIBERS_URL ); $this->prepare_request( $url ); $this->make_remote_request(); if ( $this->response->ERROR || ! $this->response->DATA['contacts'] ) { return false; } return $this->response->DATA['contacts'][0]; } protected function _get_folder_id() { if ( ! empty( $this->data['folder_id'] ) ) { return $this->data['folder_id']; } $this->prepare_request( "{$this->BASE_URL}/{$this->data['account_id']}/c" ); $this->make_remote_request(); if ( isset( $this->response->DATA['clientfolders'][0]['clientFolderId'] ) ) { $this->data['folder_id'] = $this->response->DATA['clientfolders'][0]['clientFolderId']; } return $this->data['folder_id']; } protected function _process_custom_fields( $args ) { if ( ! isset( $args['custom_fields'] ) ) { return $args; } $fields = $args['custom_fields']; unset( $args['custom_fields'] ); foreach ( $fields as $field_id => $value ) { if ( is_array( $value ) && $value ) { // This is a multiple choice field (eg. checkbox, radio, select) $value = array_values( $value ); if ( count( $value ) > 1 ) { $value = implode( ',', $value ); } else { $value = array_pop( $value ); } } self::$_->array_set( $args, $field_id, $value ); } return $args; } protected function _set_urls() { $this->_set_custom_headers(); $account_id = $this->_get_account_id(); $folder_id = $this->_get_folder_id(); $this->BASE_URL = "{$this->BASE_URL}/{$account_id}/c/{$folder_id}"; $this->FIELDS_URL = "{$this->BASE_URL}/customfields"; $this->LISTS_URL = "{$this->BASE_URL}/lists"; $this->SUBSCRIBE_URL = "{$this->BASE_URL}/subscriptions"; $this->SUBSCRIBERS_URL = "{$this->BASE_URL}/contacts"; } /** * @inheritDoc */ public function get_account_fields() { return array( 'client_id' => array( 'label' => esc_html__( 'App ID', 'et_core' ), ), 'username' => array( 'label' => esc_html__( 'Username', 'et_core' ), ), 'password' => array( 'label' => esc_html__( 'App Password', 'et_core' ), ), ); } /** * @inheritDoc */ public function get_data_keymap( $keymap = array() ) { $keymap = array( 'list' => array( 'list_id' => 'listId', 'name' => 'name', 'subscribers_count' => 'total', ), 'subscriber' => array( 'name' => 'firstName', 'last_name' => 'lastName', 'email' => 'email', 'list_id' => 'listId', 'custom_fields' => 'custom_fields', ), 'subscriptions' => array( 'list_id' => 'listId', 'message_id' => 'confirmationMessageId', ), 'custom_field' => array( 'field_id' => 'privateName', 'name' => 'publicName', 'type' => 'fieldType', 'hidden' => '!displayToUser', ), ); return parent::get_data_keymap( $keymap ); } /** * @inheritDoc */ public function fetch_subscriber_lists() { if ( empty( $this->data['client_id'] ) || empty( $this->data['username'] ) || empty( $this->data['password'] ) ) { return $this->API_KEY_REQUIRED; } $this->_set_urls(); $this->response_data_key = 'lists'; return parent::fetch_subscriber_lists(); } /** * @inheritDoc */ public function subscribe( $args, $url = '' ) { if ( empty( $this->data['client_id'] ) || empty( $this->data['username'] ) || empty( $this->data['password'] ) ) { return $this->API_KEY_REQUIRED; } $this->_set_urls(); if ( $this->_get_subscriber( $args ) ) { // Subscriber exists and is already subscribed to the list. return 'success'; } if ( ! $contact = $this->_get_subscriber( $args, 'list_id' ) ) { // Create new contact $body = $this->transform_data_to_provider_format( $args, 'subscriber' ); $body = $this->_process_custom_fields( $body ); $this->prepare_request( $this->SUBSCRIBERS_URL, 'POST', false, array( $body ), true ); $this->make_remote_request(); if ( $this->response->ERROR ) { return $this->get_error_message(); } $contact = $this->response->DATA['contacts'][0]; } // Subscribe contact to list $body = $this->transform_data_to_provider_format( $args, 'subscriptions' ); $body['contactId'] = $contact['contactId']; $body['status'] = isset( $args['message_id'] ) ? 'pending' : 'normal'; $this->prepare_request( $this->SUBSCRIBE_URL, 'POST', false, array( $body ), true ); return parent::subscribe( $args, $this->SUBSCRIBE_URL ); } } email/Ontraport.php000064400000016741152214676150010356 0ustar00_maybe_set_custom_headers(); } protected function _fetch_custom_fields( $list_id = '', $list = array() ) { static $fields = null; if ( is_null( $fields ) ) { $this->response_data_key = null; parent::_fetch_custom_fields( $list_id, $list ); if ( $this->response->ERROR ) { et_debug( $this->get_error_message() ); return array(); } $fields = array(); $fields_unprocessed = self::$_->array_get( $this->response->DATA, 'data.[0].fields', $fields ); foreach ( $fields_unprocessed as $field_id => $field ) { if ( in_array( $field_id, array( 'firstname', 'lastname', 'email' ) ) ) { continue; } $type = $field['type']; $field['field_id'] = $field_id; $field['type'] = self::$_->array_get( $this->data_keys, "custom_field_type.{$type}", 'text' ); $fields[ $field_id ] = $this->transform_data_to_our_format( $field, 'custom_field' ); } } return $fields; } protected function _get_subscriber_list_type( $list_id ) { $sequence_key = 'seq:' . $list_id; $campaign_key = 'camp:' . $list_id; if ( isset( $this->data['lists'][ $campaign_key ] ) ) { return 'Campaign'; } if ( isset( $this->data['lists'][ $sequence_key ] ) ) { return 'Sequence'; } return 'Campaign'; } protected function _maybe_set_custom_headers() { if ( empty( $this->custom_headers ) && isset( $this->data['api_key'] ) && isset( $this->data['client_id'] ) ) { $this->custom_headers = array( 'Api-Appid' => sanitize_text_field( $this->data['client_id'] ), 'Api-Key' => sanitize_text_field( $this->data['api_key'] ), ); } } protected function _prefix_subscriber_lists( $name_prefix, $id_prefix ) { $lists = array(); foreach ( $this->data['lists'] as $list_id => $list ) { $key = $id_prefix . $list_id; if ( ! $list['name'] ) { $list['name'] = $list_id; } $lists[ $key ] = $list; $lists[ $key ]['name'] = $name_prefix . $list['name']; $lists[ $key ]['list_id'] = $key; } $this->data['lists'] = $lists; $this->save_data(); } protected function _process_custom_fields( $args ) { if ( ! isset( $args['custom_fields'] ) ) { return $args; } $fields = $args['custom_fields']; unset( $args['custom_fields'] ); foreach ( $fields as $field_id => $value ) { if ( is_array( $value ) && $value ) { // This is a multiple choice field (eg. checkbox, radio, select) $value = array_keys( $value ); if ( 'checkbox' === $this->data['custom_fields'][ $field_id ]['type'] ) { // Determine if checkbox is a single checkbox or a list. // In case of single checkbox pass `1` as a value if ( ! empty( $this->data['custom_fields'][ $field_id ]['options'] ) ) { $value = implode( '*/*', $value ); $value = "*/*{$value}*/*"; } else { $value = '1'; } } else { $value = array_pop( $value ); } } self::$_->array_set( $args, $field_id, $value ); } return $args; } /** * @inheritDoc */ public function get_account_fields() { return array( 'api_key' => array( 'label' => esc_html__( 'API Key', 'et_core' ), ), 'client_id' => array( 'label' => esc_html__( 'APP ID', 'et_core' ), ), ); } /** * @inheritDoc */ public function get_data_keymap( $keymap = array() ) { $keymap = array( 'list' => array( 'name' => 'name', 'list_id' => 'drip_id', 'subscribers_count' => 'subscriber_count', ), 'subscriber' => array( 'name' => 'firstname', 'last_name' => 'lastname', 'email' => 'email', 'custom_fields' => 'custom_fields', ), 'custom_field' => array( 'field_id' => 'field_id', 'type' => 'type', 'name' => 'alias', 'options' => 'options', ), 'custom_field_type' => array( // Us => Them 'input' => 'text', 'textarea' => 'textlong', 'checkbox' => 'list', 'select' => 'drop', // Them => Us 'text' => 'input', 'textlong' => 'textarea', 'list' => 'checkbox', 'check' => 'checkbox', 'drop' => 'select', ), ); return parent::get_data_keymap( $keymap ); } /** * @inheritDoc */ public function fetch_subscriber_lists() { if ( empty( $this->data['api_key'] ) || empty( $this->data['client_id'] ) ) { return $this->API_KEY_REQUIRED; } $this->_maybe_set_custom_headers(); $this->response_data_key = 'data'; parent::fetch_subscriber_lists(); $this->_prefix_subscriber_lists( 'Sequence: ', 'seq:' ); $sequences = $this->data['lists']; $url = 'https://api.ontraport.com/1/CampaignBuilderItems'; $url = add_query_arg( 'listFields', 'id,name,subs', $url ); $this->data_keys['list']['list_id'] = 'id'; $this->data_keys['list']['subscribers_count'] = 'subs'; $this->prepare_request( $url ); $this->response_data_key = 'data'; $result = parent::fetch_subscriber_lists(); $this->_prefix_subscriber_lists( 'Campaign: ', 'camp:' ); $this->data['lists'] = array_merge( $this->data['lists'], $sequences ); $this->save_data(); return $result; } public function get_subscriber( $email ) { $args = array( 'objectID' => '0', 'email' => rawurlencode( $email ), ); $url = add_query_arg( $args, $this->SUBSCRIBE_URL . '/object/getByEmail' ); $this->prepare_request( $url ); $this->make_remote_request(); return self::$_->array_get( $this->response->DATA, 'data.id', false ); } /** * @inheritDoc */ public function subscribe( $args, $url = '' ) { if ( empty( $this->data['api_key'] ) || empty( $this->data['client_id'] ) ) { return $this->API_KEY_REQUIRED; } $list_id = $args['list_id']; $args = $this->transform_data_to_provider_format( $args, 'subscriber' ); $args = $this->_process_custom_fields( $args ); $args['objectID'] = 0; $url = $this->SUBSCRIBE_URL . '/Contacts/saveorupdate'; // Create or update contact $this->prepare_request( $url, 'POST', false, $args ); $this->make_remote_request(); if ( $this->response->ERROR ) { return $this->get_error_message(); } $list_id_parts = explode( ':', $list_id ); $list_id = array_pop( $list_id_parts ); $data = $this->response->DATA['data']; // Subscribe contact to list $url = $this->SUBSCRIBE_URL . '/objects/subscribe'; $args = array( 'ids' => self::$_->array_get( $data, 'id', $data['attrs']['id'] ), 'add_list' => $list_id, 'sub_type' => $this->_get_subscriber_list_type( $list_id ), 'objectID' => 0, ); $this->prepare_request( $url, 'PUT', false, $args ); return parent::subscribe( $args, $url ); } } email/HubSpot.php000064400000023104152214676150007741 0ustar00_maybe_set_custom_headers(); } protected function _fetch_custom_fields( $list_id = '', $list = array() ) { $this->response_data_key = false; $fields_unprocessed = parent::_fetch_custom_fields( $list_id, $list ); $fields = array(); foreach ( $fields_unprocessed as $field ) { $field_id = $field['field_id']; if ( ! isset( $field['options'] ) ) { $fields[ $field_id ] = $field; continue; } $options = array(); foreach ( $field['options'] as $option ) { $option = $this->transform_data_to_our_format( $option, 'custom_field_option' ); $id = $option['id']; $options[ $id ] = $option['name']; } $field['options'] = $options; $fields[ $field_id ] = $field; } return $fields; } /** * Whether current request needs API Key instead. * * It's needed to check existing API Key implementation when no Access Token presents. * * @since 4.18.1 * * @return boolean API Key status. */ protected function _is_api_key_needed() { // Bail early if Access Token exists. if ( ! empty( $this->data['token'] ) ) { return false; } // Otherwise check API Key. return ! empty( $this->data['api_key'] ); } /** * Get list add contact URL. * * @since 3.0.72 * @since 4.18.1 Replaces hapikey query string with authentication on headers. * * @param string $list_id List ID. * * @return string URL for adding contact to list. */ protected function _get_list_add_contact_url( $list_id ) { $url = "{$this->BASE_URL}/lists/{$list_id}/add"; if ( $this->_is_api_key_needed() ) { $url = add_query_arg( 'hapikey', $this->data['api_key'], $url ); } return $url; } /** * Maybe need to set custom headers. * * @since 4.18.1 */ protected function _maybe_set_custom_headers() { if ( ! empty( $this->custom_headers ) ) { return; } if ( ! empty( $this->data['token'] ) ) { $this->custom_headers = array( 'authorization' => 'Bearer ' . sanitize_text_field( $this->data['token'] ), ); } } /** * Maybe set URLs. * * @since 3.0.72 * @since 4.18.1 Replaces hapikey query string with access token headers. * * @param string $email Contact email. */ protected function _maybe_set_urls( $email = '' ) { // Only use `hapikey` when Access Token doesn't exist and the API Key not empty. if ( $this->_is_api_key_needed() ) { $this->FIELDS_URL = add_query_arg( 'hapikey', $this->data['api_key'], $this->FIELDS_URL ); // phpcs:ignore ET.Sniffs.ValidVariableName.UsedPropertyNotSnakeCase -- Widely used on all email provider classes. $this->LISTS_URL = add_query_arg( 'hapikey', $this->data['api_key'], $this->LISTS_URL ); // phpcs:ignore ET.Sniffs.ValidVariableName.UsedPropertyNotSnakeCase -- Widely used on all email provider classes. $this->SUBSCRIBE_URL = add_query_arg( 'hapikey', $this->data['api_key'], $this->SUBSCRIBE_URL ); // phpcs:ignore ET.Sniffs.ValidVariableName.UsedPropertyNotSnakeCase -- Widely used on all email provider classes. } if ( $email ) { $this->SUBSCRIBE_URL = str_replace( '@email@', rawurlencode( $email ), $this->SUBSCRIBE_URL ); } } protected function _process_custom_fields( $args ) { $args['properties'] = array(); if ( ! isset( $args['custom_fields'] ) ) { return $args; } $fields = $args['custom_fields']; $properties = array(); unset( $args['custom_fields'] ); $field_types = array( 'radio', 'booleancheckbox', ); foreach ( $fields as $field_id => $value ) { if ( is_array( $value ) && $value ) { // This is a multiple choice field (eg. checkbox, radio, select) $value = array_values( $value ); $value = implode( ';', $value ); } elseif ( in_array( $this->data['custom_fields'][ $field_id ]['type'], $field_types, true ) ) { // Should use array key. Sometimes it's different than value and Hubspot expects the key $radio_options = $this->data['custom_fields'][ $field_id ]['options']; $value = array_search( $value, $radio_options ); } $properties[] = array( 'property' => $field_id, 'value' => $value, ); } $args['properties'] = $properties; return $args; } /** * @inheritDoc * * @since 4.18.1 Replaces api_key field with token. */ public function get_account_fields() { return array( 'token' => array( 'label' => esc_html__( 'Access Token', 'et_core' ), ), ); } /** * @inheritDoc */ public function get_data_keymap( $keymap = array() ) { $keymap = array( 'list' => array( 'list_id' => 'listId', 'name' => 'name', 'subscribers_count' => 'metaData.size', ), 'subscriber' => array( 'email' => 'email', 'name' => 'firstname', 'last_name' => 'lastname', 'custom_fields' => 'custom_fields', ), 'error' => array( 'error_message' => 'message', ), 'custom_field' => array( 'field_id' => 'name', 'name' => 'label', 'type' => 'fieldType', 'options' => 'options', 'hidden' => 'hidden', ), 'custom_field_option' => array( 'id' => 'value', 'name' => 'label', ), 'custom_field_type' => array( // Us <=> Them 'select' => 'select', 'radio' => 'radio', 'checkbox' => 'checkbox', // Us => Them 'input' => 'text', 'textarea' => 'text', // Them => Us 'text' => 'input', 'booleancheckbox' => 'booleancheckbox', ), ); return parent::get_data_keymap( $keymap ); } /** * @inheritDoc * * @since 4.18.1 Replaces API Key usage with Access Token. */ public function fetch_subscriber_lists() { if ( empty( $this->data['token'] ) && empty( $this->data['api_key'] ) ) { return self::$TOKEN_REQUIRED; // phpcs:ignore ET.Sniffs.ValidVariableName.UsedPropertyNotSnakeCase -- Widely used on all email provider classes. } $this->_maybe_set_custom_headers(); $this->_maybe_set_urls(); /** * The maximum number of subscriber lists to request from Hubspot's API at a time. * * @since 3.0.75 * * @param int $max_lists Value must be <= 250. */ $max_lists = (int) apply_filters( 'et_core_api_email_hubspot_max_lists', 250 ); $this->LISTS_URL = add_query_arg( 'count', $max_lists, $this->LISTS_URL ); $this->response_data_key = 'lists'; return parent::fetch_subscriber_lists(); } /** * @inheritDoc * * @since 4.18.1 Replaces API Key usage with Access Token. */ public function subscribe( $args, $url = '' ) { if ( empty( $this->data['token'] ) && empty( $this->data['api_key'] ) ) { return self::$TOKEN_REQUIRED; // phpcs:ignore ET.Sniffs.ValidVariableName.UsedPropertyNotSnakeCase -- Widely used on all email provider classes. } $this->_maybe_set_custom_headers(); $this->_maybe_set_urls( $args['email'] ); $args = $this->_process_custom_fields( $args ); $data = array( 'properties' => array( array( 'property' => 'email', 'value' => et_core_sanitized_previously( $args['email'] ), ), array( 'property' => 'firstname', 'value' => et_core_sanitized_previously( $args['name'] ), ), array( 'property' => 'lastname', 'value' => et_core_sanitized_previously( $args['last_name'] ), ), ), ); $data['properties'] = array_merge( $data['properties'], $args['properties'] ); $this->prepare_request( $this->SUBSCRIBE_URL, 'POST', false, $data, true ); $this->make_remote_request(); if ( $this->response->ERROR ) { return $this->get_error_message(); } $url = $this->_get_list_add_contact_url( $args['list_id'] ); $data = array( 'emails' => array( $args['email'] ), ); $this->prepare_request( $url, 'POST', false, $data, true ); $this->make_remote_request(); if ( $this->response->ERROR ) { return $this->get_error_message(); } return 'success'; } } email/SendinBlue.php000064400000020354152214676150010411 0ustar00_maybe_set_custom_headers(); } protected function _maybe_set_custom_headers() { if ( empty( $this->custom_headers ) && isset( $this->data['api_key'] ) ) { $this->custom_headers = array( 'api-key' => $this->data['api_key'] ); } } protected function _process_custom_fields( $args ) { if ( ! isset( $args['custom_fields'] ) ) { return $args; } $fields = $args['custom_fields']; $fileds_info = $args['fileds_info']; unset( $args['custom_fields'] ); foreach ( $fields as $field_id => $value ) { if ( ! isset( $fileds_info[ $field_id ] ) ) { continue; } if ( is_array( $value ) && $value ) { // This is a multiple choice field (eg. checkbox, radio, select) $value = array_values( $value ); if ( count( $value ) > 1 ) { $value = implode( ',', $value ); } else { $type = self::$_->array_get( $fileds_info, "{$field_id}.native_type" ); // User checked the checkbox, when native type is Boolean. $value = 'boolean' === $type ? true : array_pop( $value ); } } self::$_->array_set( $args, "attributes.{$field_id}", $value ); } return $args; } /** * @inheritDoc */ public function get_account_fields() { return array( 'api_key' => array( 'label' => esc_html__( 'API Key', 'et_core' ), ), ); } /** * @inheritDoc */ public function get_data_keymap( $keymap = array() ) { $keymap = array( 'list' => array( 'list_id' => 'id', 'name' => 'name', 'subscribers_count' => $this->_should_use_legacy_api() ? 'total_subscribers' : 'totalSubscribers', ), 'subscriber' => array( 'email' => 'email', 'name' => 'attributes.FIRSTNAME', 'last_name' => 'attributes.LASTNAME', 'list_id' => $this->_should_use_legacy_api() ? '@listid' : '@listIds', 'custom_fields' => 'custom_fields', 'updateEnabled' => 'updateEnabled', ), 'custom_field' => array( 'native_type' => 'type', 'field_id' => 'name', 'name' => 'name', ), ); return parent::get_data_keymap( $keymap ); } public function get_subscriber( $email ) { $this->prepare_request( "{$this->USERS_URL}/{$email}", 'GET' ); $this->make_remote_request(); if ( $this->response->ERROR || ! isset( $this->response->DATA['listid'] ) ) { return false; } if ( isset( $this->response->DATA['code'] ) && 'success' !== $this->response->DATA['code'] ) { return false; } return $this->response->DATA; } /** * @inheritDoc */ public function fetch_subscriber_lists() { if ( empty( $this->data['api_key'] ) ) { return $this->API_KEY_REQUIRED; } if ( empty( $this->custom_headers ) ) { $this->_maybe_set_custom_headers(); } $use_legacy_api = $this->_should_use_legacy_api(); if ( $use_legacy_api ) { $this->LISTS_URL = 'https://api.sendinblue.com/v2.0/list'; // @phpcs:ignore ET.Sniffs.ValidVariableName.UsedPropertyNotSnakeCase -- Keep the variable name. $this->response_data_key = 'data'; $params = array( 'page' => 1, 'page_limit' => 2, ); } else { $this->response_data_key = 'lists'; $params = array(); } /** * The maximum number of subscriber lists to request from Sendinblue's API. * * @since 4.11.4 * * @param int $max_lists */ $max_lists = (int) apply_filters( 'et_core_api_email_sendinblue_max_lists', 50 ); $url = "{$this->LISTS_URL}?limit={$max_lists}&offset=0&sort=desc"; $this->prepare_request( $url, 'GET', false, $params ); $this->request->data_format = 'body'; parent::fetch_subscriber_lists(); if ( $this->response->ERROR ) { return $this->response->ERROR_MESSAGE; } if ( isset( $this->response->DATA['code'] ) && 'success' !== $this->response->DATA['code'] ) { return $this->response->DATA['message']; } $result = 'success'; $this->data['is_authorized'] = 'true'; $list_data = $use_legacy_api ? $this->response->DATA['data']['lists'] : ( isset( $this->response->DATA['lists'] ) ? $this->response->DATA['lists'] : [] ); if ( ! empty( $list_data ) ) { $this->data['lists'] = $this->_process_subscriber_lists( $list_data ); $this->save_data(); } return $result; } /** * Get custom fields for a subscriber list. * Need to override the method in the child class to dynamically use the API endpoint * and response_data_key based on the API version being used. * * @param int|string $list_id The list ID. * @param array $list The lists array. * * @return array */ protected function _fetch_custom_fields( $list_id = '', $list = array() ) { if ( $this->_should_use_legacy_api() ) { $this->FIELDS_URL = 'https://api.sendinblue.com/v2.0/attribute/normal'; // @phpcs:ignore ET.Sniffs.ValidVariableName.UsedPropertyNotSnakeCase -- Keep the variable name. $this->response_data_key = 'data'; } else { $this->response_data_key = 'attributes'; } return parent::_fetch_custom_fields( $list_id, $list ); } /** * @inheritDoc */ public function subscribe( $args, $url = '' ) { $args['list_id'] = array( absint( $args['list_id'] ) ); // in V3 the list id has to be integer. if ( $this->_should_use_legacy_api() ) { $this->SUBSCRIBE_URL = 'https://api.sendinblue.com/v2.0/user/createdituser'; // @phpcs:ignore ET.Sniffs.ValidVariableName.UsedPropertyNotSnakeCase -- Keep the variable name. $existing_user = $this->get_subscriber( $args['email'] ); if ( false !== $existing_user ) { $args['list_id'] = array_unique( array_merge( $args['list_id'], $existing_user['listid'] ) ); } } else { $args['updateEnabled'] = true; // Update existing contact if exists. // Process data and encode to json, the new API (v3) uses json encoded body params. if ( ! in_array( 'ip_address', $args, true ) || 'true' === $args['ip_address'] ) { $args['ip_address'] = et_core_get_ip_address(); } elseif ( 'false' === $args['ip_address'] ) { $args['ip_address'] = '0.0.0.0'; } $args = $this->transform_data_to_provider_format( $args, 'subscriber' ); if ( $this->custom_fields ) { $args['fileds_info'] = $this->_fetch_custom_fields(); $args = $this->_process_custom_fields( $args ); } $this->prepare_request( $this->SUBSCRIBE_URL, 'POST', false, $args, true ); // @phpcs:ignore ET.Sniffs.ValidVariableName.UsedPropertyNotSnakeCase -- Keep the variable name. } return parent::subscribe( $args, $this->SUBSCRIBE_URL ); } /** * Check if the api-key being used is legacy (v2). * * @return boolean */ protected function _should_use_legacy_api() { $api_key = isset( $this->data['api_key'] ) ? $this->data['api_key'] : ''; return ! empty( $api_key ) && 'xkeysib-' !== substr( $api_key, 0, 8 ); } } email/ConvertKit.php000064400000013045152214676150010450 0ustar00LISTS_URL = "{$this->BASE_URL}/forms"; } protected function _fetch_custom_fields( $list_id = '', $list = array() ) { $this->response_data_key = 'custom_fields'; $this->prepare_request( $this->_generate_url_for_request( "{$this->BASE_URL}/custom_fields" ) ); return parent::_fetch_custom_fields( $list_id, $list ); } /** * Generates the URL for adding subscribers. * * @param $list_id * * @since 1.1.0 * * @return string */ protected function _get_subscribe_url( $list_id ) { return "{$this->LISTS_URL}/{$list_id}/subscribe"; } protected function _get_subscriber_counts( $forms ) { $result = array(); foreach ( (array) $forms as $form_info ) { $url = $this->_generate_url_for_request( "{$this->LISTS_URL}/{$form_info['id']}/subscriptions", true ); $this->prepare_request( $url ); $this->make_remote_request(); if ( $this->response->ERROR || ! isset( $this->response->DATA['total_subscriptions'] ) ) { continue; } $form_info['total_subscriptions'] = $this->response->DATA['total_subscriptions']; $result[] = $form_info; } return $result; } /** * Adds default args for all API requests to given url. * * @since 1.1.0 * * @param string $url * @param bool $with_secret * * @return string */ protected function _generate_url_for_request( $url, $with_secret = false ) { $key = $with_secret ? $this->data['api_secret'] : $this->data['api_key']; $key_type = $with_secret ? 'api_secret' : 'api_key'; return esc_url_raw( add_query_arg( $key_type, $key, $url ) ); } protected function _process_custom_fields( $args ) { if ( ! isset( $args['custom_fields'] ) ) { return $args; } $fields = $args['custom_fields']; unset( $args['custom_fields'] ); foreach ( $fields as $field_id => $value ) { if ( is_array( $value ) && $value ) { // This is a multiple choice field (eg. checkbox, radio, select) $value = array_values( $value ); if ( count( $value ) > 1 ) { $value = implode( ',', $value ); } else { $value = array_pop( $value ); } } self::$_->array_set( $args, "fields.{$field_id}", $value ); } return $args; } /** * @inheritDoc */ public function get_account_fields() { return array( 'api_key' => array( 'label' => esc_html__( 'API Key', 'et_core' ), ), 'api_secret' => array( 'label' => esc_html__( 'API Secret', 'et_core' ), ), ); } /** * @inheritDoc */ public function get_data_keymap( $keymap = array() ) { $keymap = array( 'list' => array( 'list_id' => 'id', 'name' => 'name', 'subscribers_count' => 'total_subscriptions', ), 'subscriber' => array( 'email' => 'email', 'name' => 'first_name', 'custom_fields' => 'custom_fields', ), 'error' => array( 'error_message' => 'message', ), 'custom_field' => array( 'field_id' => 'key', 'name' => 'label', ), ); return parent::get_data_keymap( $keymap ); } /** * @inheritDoc */ public function fetch_subscriber_lists() { if ( empty( $this->data['api_key'] ) ) { return $this->API_KEY_REQUIRED; } $url = $this->_generate_url_for_request( $this->LISTS_URL ); $result = 'success'; $this->response_data_key = ''; $this->prepare_request( $url ); parent::fetch_subscriber_lists(); if ( ! $this->response->ERROR && ! empty( $this->response->DATA['forms'] ) ) { /** * We need to store `$forms` to avoid using mutated `$this->response->DATA['forms']` down the line. * * `$this->response->DATA['forms']` will be mutated to `NULL` in this code block since it is a shared state * and is used by other functions all over. This fixes the issue. * * @see: https://github.com/elegantthemes/Divi/issues/25296 */ $forms = $this->response->DATA['forms']; $with_subscriber_counts = $this->_get_subscriber_counts( $forms ); $this->data['lists'] = $this->_process_subscriber_lists( $with_subscriber_counts ); $this->data['is_authorized'] = 'true'; $this->data['custom_fields'] = $this->_fetch_custom_fields( '', array_shift( $forms ) ); $this->save_data(); } elseif ( $this->response->ERROR ) { $result = $this->get_error_message(); } return $result; } /** * @inheritDoc */ public function subscribe( $args, $url = '' ) { $url = $this->_generate_url_for_request( $this->_get_subscribe_url( $args['list_id'] ) ); $params = $this->transform_data_to_provider_format( $args, 'subscriber' ); $params = $this->_process_custom_fields( $params ); $params['fields']['notes'] = $this->SUBSCRIBED_VIA; $this->prepare_request( $url, 'POST', false, $params ); return parent::subscribe( $params, $url ); } } email/MailerLite.php000064400000006046152214676150010412 0ustar00_maybe_set_custom_headers(); } protected function _maybe_set_custom_headers() { if ( empty( $this->custom_headers ) && isset( $this->data['api_key'] ) ) { $this->custom_headers = array( 'X-MailerLite-ApiKey' => "{$this->data['api_key']}" ); } } protected function _process_custom_fields( $args ) { if ( ! isset( $args['custom_fields'] ) ) { return $args; } $fields = $args['custom_fields']; unset( $args['custom_fields'] ); foreach ( $fields as $field_id => $value ) { if ( is_array( $value ) && $value ) { // This is a multiple choice field (eg. checkbox, radio, select) $value = array_values( $value ); if ( count( $value ) > 1 ) { $value = implode( ',', $value ); } else { $value = array_pop( $value ); } } self::$_->array_set( $args, "fields.{$field_id}", $value ); } return $args; } /** * @inheritDoc */ public function get_account_fields() { return array( 'api_key' => array( 'label' => esc_html__( 'API Key', 'et_core' ), ), ); } /** * @inheritDoc */ public function get_data_keymap( $keymap = array() ) { $keymap = array( 'list' => array( 'list_id' => 'id', 'name' => 'name', 'subscribers_count' => 'active', ), 'subscriber' => array( 'name' => 'fields.name', 'last_name' => 'fields.last_name', 'email' => 'email', 'custom_fields' => 'custom_fields', 'resubscribe' => 'resubscribe', ), 'error' => array( 'error_message' => 'error.message', ), 'custom_field' => array( 'field_id' => 'key', 'name' => 'title', ), ); return parent::get_data_keymap( $keymap ); } /** * @inheritDoc */ public function fetch_subscriber_lists() { if ( empty( $this->data['api_key'] ) ) { return $this->API_KEY_REQUIRED; } $this->_maybe_set_custom_headers(); $this->response_data_key = false; return parent::fetch_subscriber_lists(); } /** * @inheritDoc */ public function subscribe( $args, $url = '' ) { $args['resubscribe'] = 1; $url = "{$this->LISTS_URL}/{$args['list_id']}/subscribers"; return parent::subscribe( $args, $url ); } } email/Mailster.php000064400000013053152214676150010137 0ustar00owner ); if ( 'bloom' === $this->owner && isset( $args['optin_id'] ) ) { $optin_form = ET_Bloom::get_this()->dashboard_options[ $args['optin_id'] ]; $optin_name = $optin_form['optin_name']; } return sprintf( '%1$s %2$s "%3$s" on %4$s', esc_html( $owner ), esc_html__( 'Opt-in', 'et_core' ), esc_html( $optin_name ), wp_get_referer() ); } protected function _fetch_custom_fields( $list_id = '', $list = array() ) { static $fields = null; if ( is_null( $fields ) ) { $customfields = mailster()->get_custom_fields(); if ( empty( $customfields ) ) { return $fields; } $field_types = self::$_->array_get( $this->data_keys, 'custom_field_type' ); foreach ( $customfields as $field_id => $field ) { $field = $this->transform_data_to_our_format( $field, 'custom_field' ); $type = self::$_->array_get( $field, 'type', 'any' ); $field['field_id'] = $field_id; if ( $field_types && ! isset( $field_types[ $type ] ) ) { // Unsupported field type. Make it 'text' instead. $type = 'textfield'; } $field['type'] = self::$_->array_get( $this->data_keys, "custom_field_type.{$type}", 'input' ); $fields[ $field_id ] = $field; } } return $fields; } protected function _process_custom_fields( $args ) { if ( ! isset( $args['custom_fields'] ) ) { return $args; } $fields = $args['custom_fields']; unset( $args['custom_fields'] ); $registered_custom_fields = self::$_->array_get( $this->data, 'custom_fields', array() ); foreach ( $fields as $field_id => $value ) { $field_type = isset( $registered_custom_fields[ $field_id ] ) && isset( $registered_custom_fields[ $field_id ]['type'] ) ? $registered_custom_fields[ $field_id ]['type'] : false; // Mailster doesn't support multiple checkboxes and if it appears here that means the checkbox is checked if ( 'checkbox' === $field_type ) { $value = 1; } if ( is_array( $value ) && $value ) { // This is a multiple choice field (eg. radio, select) $value = array_values( $value ); if ( count( $value ) > 1 ) { $value = implode( ',', $value ); } else { $value = array_pop( $value ); } } self::$_->array_set( $args, $field_id, $value ); } return $args; } /** * @inheritDoc */ public function get_account_fields() { return array(); } /** * @inheritDoc */ public function get_data_keymap( $keymap = array() ) { $keymap = array( 'list' => array( 'list_id' => 'ID', 'name' => 'name', 'subscribers_count' => 'subscribers', ), 'subscriber' => array( 'dbl_optin' => 'status', 'email' => 'email', 'last_name' => 'lastname', 'name' => 'firstname', 'custom_fields' => 'custom_fields', ), 'custom_field' => array( 'name' => 'name', 'type' => 'type', 'options' => 'values', 'hidden' => 'hidden', ), 'custom_field_type' => array( // Us => Them 'textarea' => 'textarea', 'radio' => 'radio', 'checkbox' => 'checkbox', 'input' => 'textfield', 'select' => 'dropdown', // Them => Us 'textfield' => 'input', 'dropdown' => 'select', ), ); return parent::get_data_keymap( $keymap ); } public function fetch_subscriber_lists() { if ( ! function_exists( 'mailster' ) ) { return esc_html__( 'Mailster Newsletter Plugin is not enabled!', 'et_core' ); } $lists = mailster( 'lists' )->get( null, null, true ); $error_message = esc_html__( 'No lists were found. Please create a Mailster list first!', 'et_core' ); if ( $lists ) { $error_message = 'success'; $this->data['lists'] = $this->_process_subscriber_lists( $lists ); $this->data['is_authorized'] = true; $this->data['custom_fields'] = $this->_fetch_custom_fields(); $this->save_data(); } return $error_message; } /** * @inheritDoc */ public function subscribe( $args, $url = '' ) { $error = esc_html__( 'An error occurred. Please try again later.', 'et_core' ); if ( ! function_exists( 'mailster' ) ) { return $error; } $params = $this->transform_data_to_provider_format( $args, 'subscriber', array( 'dbl_optin' ) ); $params = $this->_process_custom_fields( $params ); $extra_params = array( 'status' => 'disable' === $args['dbl_optin'] ? 1 : 0, 'referrer' => $this->_get_referrer( $args ), ); $params = array_merge( $params, $extra_params ); $subscriber_id = mailster( 'subscribers' )->merge( $params ); if ( is_wp_error( $subscriber_id ) ) { $result = htmlspecialchars_decode( $subscriber_id->get_error_message() ); } else if ( mailster( 'subscribers' )->assign_lists( $subscriber_id, $args['list_id'], false ) ) { $result = 'success'; } else { $result = $error; } return $result; } } email/MadMimi.php000064400000007251152214676150007677 0ustar00_maybe_set_urls(); } protected function _maybe_set_urls( $list_id = '' ) { if ( ! empty( $this->data['api_key'] ) && ! empty( $this->data['username'] ) ) { $args = array( 'username' => rawurlencode( $this->data['username'] ), 'api_key' => $this->data['api_key'], ); $this->LISTS_URL = add_query_arg( $args, $this->LISTS_URL ); $this->SUBSCRIBE_URL = add_query_arg( $args, $this->SUBSCRIBE_URL ); if ( $list_id ) { $this->SUBSCRIBE_URL = str_replace( '@list_id@', rawurlencode( $list_id ), $this->SUBSCRIBE_URL ); } } } protected function _process_custom_fields( $args ) { if ( ! isset( $args['custom_fields'] ) ) { return $args; } $fields = $args['custom_fields']; unset( $args['custom_fields'] ); foreach ( $fields as $field_id => $value ) { if ( is_array( $value ) && $value ) { // This is a multiple choice field (eg. checkbox, radio, select) $value = array_values( $value ); if ( count( $value ) > 1 ) { $value = implode( ',', $value ); } else { $value = array_pop( $value ); } } self::$_->array_set( $args, $field_id, $value ); } return $args; } /** * @inheritDoc */ public function get_account_fields() { return array( 'username' => array( 'label' => esc_html__( 'Username', 'et_core' ), ), 'api_key' => array( 'label' => esc_html__( 'API Key', 'et_core' ), ), ); } /** * @inheritDoc */ public function get_data_keymap( $keymap = array() ) { $keymap = array( 'list' => array( 'list_id' => 'id', 'name' => 'name', 'subscribers_count' => 'list_size', ), 'subscriber' => array( 'name' => 'first_name', 'last_name' => 'last_name', 'email' => 'email', 'custom_fields' => 'custom_fields', ), ); return parent::get_data_keymap( $keymap ); } /** * @inheritDoc */ public function fetch_subscriber_lists() { if ( empty( $this->data['api_key'] ) || empty( $this->data['username'] ) ) { return $this->API_KEY_REQUIRED; } $this->_maybe_set_urls(); $this->response_data_key = false; return parent::fetch_subscriber_lists(); } /** * @inheritDoc */ public function subscribe( $args, $url = '' ) { if ( empty( $this->data['api_key'] ) || empty( $this->data['username'] ) ) { return $this->API_KEY_REQUIRED; } $this->_maybe_set_urls( $args['list_id'] ); $ip_address = 'true' === self::$_->array_get( $args, 'ip_address', 'true' ) ? et_core_get_ip_address() : '0.0.0.0'; $args = $this->transform_data_to_provider_format( $args, 'subscriber' ); $args = $this->_process_custom_fields( $args ); $args['ip_address'] = $ip_address; $args['subscribed_via'] = $this->SUBSCRIBED_VIA; $this->SUBSCRIBE_URL = add_query_arg( $args, $this->SUBSCRIBE_URL ); $this->prepare_request( $this->SUBSCRIBE_URL, 'POST', false ); return parent::subscribe( $args, $url ); } } email/ConstantContact.php000064400000013722152214676150011467 0ustar00_maybe_set_custom_headers(); } protected function _create_subscriber_data_array( $args ) { return $this->transform_data_to_provider_format( $args, 'subscriber' ); } protected function _fetch_custom_fields( $list_id = '', $list = array() ) { $fields = array(); foreach ( range( 1, 15 ) as $i ) { $fields["custom_field_{$i}"] = array( 'field_id' => "custom_field_{$i}", 'name' => "custom_field_{$i}", 'type' => 'any', ); } return $fields; } protected function _get_list_from_subscriber( $subscriber, $list_id ) { if ( ! isset( $subscriber['lists'] ) ) { return false; } foreach ( $subscriber['lists'] as &$list ) { if ( $list['id'] === $list_id ) { return $list; } } return false; } protected function _maybe_set_custom_headers() { if ( empty( $this->custom_headers ) && isset( $this->data['token'] ) ) { $this->custom_headers = array( 'Authorization' => 'Bearer ' . sanitize_text_field( $this->data['token'] ), ); } } protected function _process_custom_fields( $args ) { if ( ! isset( $args['custom_fields'] ) ) { return $args; } $fields = $args['custom_fields']; $processed_fields = array(); unset( $args['custom_fields'], $this->_subscriber['custom_fields_unprocessed'] ); foreach ( $fields as $field_id => $value ) { if ( is_array( $value ) && $value ) { // This is a multiple choice field (eg. checkbox, radio, select) $value = array_values( $value ); if ( count( $value ) > 1 ) { $value = implode( ',', $value ); } else { $value = array_pop( $value ); } } $processed_fields[] = array( 'name' => $field_id, 'value' => $value, ); } if ( isset( $this->_subscriber['custom_fields'] ) ) { $processed_fields = array_merge( $processed_fields, $this->_subscriber['custom_fields'] ); } $this->_subscriber['custom_fields'] = array_unique( $processed_fields, SORT_REGULAR ); return $args; } /** * @inheritDoc */ public function get_account_fields() { return array( 'api_key' => array( 'label' => esc_html__( 'API Key', 'et_core' ), ), 'token' => array( 'label' => esc_html__( 'Access Token', 'et_core' ), ), ); } /** * @inheritDoc */ public function get_data_keymap( $keymap = array() ) { $keymap = array( 'list' => array( 'list_id' => 'id', 'name' => 'name', 'subscribers_count' => 'contact_count', ), 'subscriber' => array( 'name' => 'first_name', 'last_name' => 'last_name', 'email' => 'email_addresses.[0].email_address', 'list_id' => 'lists.[0].id', 'custom_fields' => 'custom_fields_unprocessed', ), 'error' => array( 'error_message' => '[0].error_message', ), 'custom_field' => array( 'field_id' => 'name', 'name' => 'name', ), ); return parent::get_data_keymap( $keymap ); } public function get_subscriber( $email ) { $url = add_query_arg( 'email', $email, $this->SUBSCRIBERS_URL ); $this->prepare_request( $url, 'GET', false ); $this->make_remote_request(); if ( $this->response->ERROR || ! isset( $this->response->DATA['results'] ) ) { return array(); } return $this->response->DATA['results']; } /** * @inheritDoc */ public function fetch_subscriber_lists() { if ( empty( $this->data['api_key'] ) || empty( $this->data['token'] ) ) { return $this->API_KEY_REQUIRED; } $this->_maybe_set_custom_headers(); $this->response_data_key = false; $this->LISTS_URL = add_query_arg( 'api_key', $this->data['api_key'], $this->LISTS_URL ); return parent::fetch_subscriber_lists(); } /** * @inheritDoc */ public function subscribe( $args, $url = '' ) { $this->SUBSCRIBERS_URL = add_query_arg( 'api_key', $this->data['api_key'], $this->SUBSCRIBERS_URL ); $result = null; $args['list_id'] = (string) $args['list_id']; $subscriber = $this->get_subscriber( $args['email'] ); $subscriber = $subscriber ? $subscriber[0] : $subscriber; $query_args = array( 'api_key' => $this->data['api_key'], 'action_by' => 'ACTION_BY_VISITOR' ); if ( $subscriber ) { if ( $list = $this->_get_list_from_subscriber( $subscriber, $args['list_id'] ) ) { $result = 'success'; } else { $subscriber['lists'][] = array( 'id' => $args['list_id'] ); $this->_subscriber = &$subscriber; $args = $this->_process_custom_fields( $args ); $url = add_query_arg( $query_args, "{$this->SUBSCRIBE_URL}/{$subscriber['id']}" ); $this->prepare_request( $url, 'PUT', false, $subscriber, true ); } } else { $url = add_query_arg( $query_args, $this->SUBSCRIBE_URL ); $subscriber = $this->_create_subscriber_data_array( $args ); $this->_subscriber = &$subscriber; $args = $this->_process_custom_fields( $args ); $this->prepare_request( $url, 'POST', false, $subscriber, true ); } if ( 'success' !== $result ) { $result = parent::subscribe( $args, $this->SUBSCRIBE_URL ); } return $result; } } email/ActiveCampaign.php000064400000020236152214676150011233 0ustar00 array( 'field_id' => '%phone%', 'hidden' => false, 'name' => 'Phone', 'type' => 'input', ), '%customer_acct_name%' => array( 'field_id' => '%customer_acct_name%', 'hidden' => false, 'name' => 'Account', 'type' => 'input', ), ); foreach ( $list['fields'] as $field ) { $field = $this->transform_data_to_our_format( $field, 'custom_field' ); $field_id = $field['field_id']; $type = $field['type']; $field['type'] = self::$_->array_get( $this->data_keys, "custom_field_type.{$type}", 'text' ); if ( isset( $field['options'] ) ) { $options = array(); foreach ( $field['options'] as $option ) { $option = $this->transform_data_to_our_format( $option, 'custom_field_option' ); $id = $option['id']; $options[ $id ] = $option['name']; } $field['options'] = $options; } $fields[ $field_id ] = $field; } return $fields; } protected function _process_custom_fields( $args ) { if ( ! isset( $args['custom_fields'] ) ) { return $args; } $fields = $args['custom_fields']; unset( $args['custom_fields'] ); foreach ( $fields as $field_id => $value ) { if ( is_array( $value ) && $value ) { // This is a multiple choice field (eg. checkbox, radio, select) $value = array_values( $value ); if ( 'checkbox' === $this->data['custom_fields'][ $field_id ]['type'] ) { $value = implode( '||', $value ); $value = "||{$value}||"; } else { $value = array_pop( $value ); } } // Check if the custom field is an ActiveCampaign general field, // it should be posted as dedicated param instead of `field[{$field_id},0]` param. if ( preg_match( '/%(.*)%/', $field_id, $matches ) ) { self::$_->array_set( $args, $matches[1], $value ); } else { self::$_->array_set( $args, "field[{$field_id},0]", $value ); } } return $args; } /** * Returns the requests URL for the account assigned to this class instance. * * @return string */ protected function _get_requests_url() { $base_url = untrailingslashit( $this->data['api_url'] ); return "{$base_url}/admin/api.php"; } /** * @inheritDoc */ public function get_account_fields() { return array( 'api_key' => array( 'label' => esc_html__( 'API Key', 'et_core' ), ), 'api_url' => array( 'label' => esc_html__( 'API URL', 'et_core' ), 'apply_password_mask' => false, ), 'form_id' => array( 'label' => esc_html__( 'Form ID', 'et_core' ), 'not_required' => true, 'apply_password_mask' => false, ), ); } /** * @inheritDoc */ public function get_data_keymap( $keymap = array() ) { $keymap = array( 'list' => array( 'list_id' => 'id', 'name' => 'name', 'subscribers_count' => 'subscriber_count', ), 'subscriber' => array( 'email' => 'email', 'last_name' => 'last_name', 'name' => 'first_name', 'custom_fields' => 'custom_fields', ), 'error' => array( 'error_message' => 'result_message', ), 'custom_field' => array( 'field_id' => 'id', 'name' => 'title', 'type' => 'type', 'hidden' => '!visible', 'options' => 'options', ), 'custom_field_option' => array( 'id' => 'value', 'name' => 'name', ), 'custom_field_type' => array( // Us <=> Them 'checkbox' => 'checkbox', 'radio' => 'radio', 'textarea' => 'textarea', 'hidden' => 'hidden', // Us => Them 'select' => 'dropdown', 'input' => 'text', // Them => Us 'dropdown' => 'select', 'text' => 'input', ), ); return parent::get_data_keymap( $keymap ); } /** * @inheritDoc */ public function fetch_subscriber_lists() { if ( empty( $this->data['api_key'] ) || empty( $this->data['api_url'] ) ) { return $this->API_KEY_REQUIRED; } $query_args = array( 'api_key' => $this->data['api_key'], 'api_action' => 'list_list', 'api_output' => 'json', 'ids' => 'all', 'full' => '1', 'global_fields' => '1', ); $request_url = add_query_arg( $query_args, $this->_get_requests_url() ); $request_url = esc_url_raw( $request_url, array( 'https' ) ); $this->prepare_request( $request_url ); $this->request->HEADERS['Content-Type'] = 'application/x-www-form-urlencoded'; parent::fetch_subscriber_lists(); if ( $this->response->ERROR ) { return $this->get_error_message(); } $lists = array(); foreach ( $this->response->DATA as $key => $list_data ) { if ( ! is_numeric( $key ) ) { continue; } if ( ! empty( $list_data ) ) { $lists[] = $list_data; } } $this->data['lists'] = $this->_process_subscriber_lists( $lists ); $this->data['custom_fields'] = $this->_fetch_custom_fields( '', array_shift( $this->response->DATA ) ); $this->data['is_authorized'] = 'true'; $this->save_data(); et_debug($this->data); return 'success'; } /** * Get ActiveCampaign subscriber info by email. * * @param string $email * * @return array */ public function get_subscriber( $email ) { $query_args = array( 'api_key' => $this->data['api_key'], 'api_action' => 'subscriber_view_email', 'api_output' => 'json', 'email' => $email, ); // Build request URL. This action only accept GET method. $request_url = add_query_arg( $query_args, $this->_get_requests_url() ); $request_url = esc_url_raw( $request_url, array( 'https' ) ); // Prepare and send the request. $this->prepare_request( $request_url ); $this->request->HEADERS['Content-Type'] = 'application/x-www-form-urlencoded'; $this->make_remote_request(); // Ensure no error happen and it's included in one of the lists. $list_id = self::$_->array_get( $this->response->DATA, 'listid', false ); $result_code = self::$_->array_get( $this->response->DATA, 'result_code', false ); if ( $this->response->ERROR || ! $list_id || ! $result_code ) { return false; } return $this->response->DATA; } /** * @inheritDoc */ public function subscribe( $args, $url= '' ) { // Ensure to skip subscribe action if current email already subscribed. $subscriber_data = $this->get_subscriber( $args['email'] ); $subscriber_lists = self::$_->array_get( $subscriber_data, 'lists', array() ); $subscriber_list = self::$_->array_get( $subscriber_lists, $args['list_id'], false ); if ( $subscriber_list ) { return 'success'; } $list_id_key = 'p[' . $args['list_id'] . ']'; $status_key = 'status[' . $args['list_id'] . ']'; $responders_key = 'instantresponders[' . $args['list_id'] . ']'; $list_id = $args['list_id']; $args = $this->transform_data_to_provider_format( $args, 'subscriber', array( 'list_id' ) ); $args = $this->_process_custom_fields( $args ); $query_args = array( 'api_key' => $this->data['api_key'], 'api_action' => 'contact_sync', 'api_output' => 'json', ); $url = esc_url_raw( add_query_arg( $query_args, $this->_get_requests_url() ) ); $args[ $list_id_key ] = $list_id; $args[ $status_key ] = 1; $args[ $responders_key ] = 1; if ( ! empty( $this->data['form_id'] ) ) { $args['form'] = (int) $this->data['form_id']; } $this->prepare_request( $url, 'POST', false, $args ); $this->request->HEADERS['Content-Type'] = 'application/x-www-form-urlencoded'; return parent::subscribe( $args, $url ); } } email/Infusionsoft.php000064400000027340152214676150011051 0ustar00 'client_id', 'api_key' => 'api_key', ); /** * @inheritDoc */ public $ACCESS_TOKEN_URL = 'https://api.infusionsoft.com/token'; /** * @inheritDoc */ public $AUTHORIZATION_URL = 'https://signin.infusionsoft.com/app/oauth/authorize'; /** * @inheritDoc */ public $BASE_URL = ''; /** * @inheritDoc * Use this variable to hold the pattern and update $BASE_URL dynamically when needed */ public $BASE_URL_PATTERN = 'https://@app_name@.infusionsoft.com/api/xmlrpc'; /** * @inheritDoc */ public $custom_fields_scope = 'account'; /** * @inheritDoc */ public $name = 'Infusionsoft'; /** * @inheritDoc */ public $oauth_version = '2.0'; /** * @inheritDoc */ public $slug = 'infusionsoft'; /** * @inheritDoc * @internal If true, oauth endpoints properties must also be defined. */ public $uses_oauth = false; public function __construct( $owner = '', $account_name = '', $api_key = '' ) { parent::__construct( $owner, $account_name, $api_key ); $this->http->expects_json = false; } protected function _add_contact_to_list( $contact_id, $list_id ) { $params = array( $this->data[ self::$_data_keys['api_key'] ], (int) $contact_id, (int) $list_id ); $data = self::$_->prepare_xmlrpc_method_call( 'ContactService.addToGroup', $params ); $this->_do_request( $data ); if ( $this->response->ERROR ) { return false; } return self::$_->process_xmlrpc_response( $this->response->DATA ); } protected function _create_contact( $contact_details ) { $params = array( $this->data[ self::$_data_keys['api_key'] ], $contact_details ); $data = self::$_->prepare_xmlrpc_method_call( 'ContactService.add', $params ); $this->_do_request( $data ); if ( $this->response->ERROR ) { return false; } $result = self::$_->process_xmlrpc_response( $this->response->DATA ); return $result; } protected function _do_request( $data ) { $this->prepare_request( $this->_get_base_url(), 'POST', false, $data ); $this->request->HEADERS = array( 'Content-Type' => 'application/xml', 'Accept-Charset' => 'UTF-8' ); $this->make_remote_request(); } protected function _fetch_custom_fields( $list_id = '', $list = array() ) { $params = array( $this->data[ self::$_data_keys['api_key'] ], 'DataFormField', 100, 0, array( 'FormId' => -1 ), array( 'Name', 'Label', 'DataType', 'Values' ) ); $data = self::$_->prepare_xmlrpc_method_call( 'DataService.query', $params ); $this->_do_request( $data ); if ( $this->response->ERROR ) { return array(); } $data = self::$_->process_xmlrpc_response( $this->response->DATA ); foreach ( $data as &$custom_field ) { $custom_field = (array) $custom_field; $custom_field = $this->transform_data_to_our_format( $custom_field, 'custom_field' ); } $fields = array(); foreach ( $data as $field ) { $field_id = $field['field_id']; $type = self::$_->array_get( $field, 'type', 'any' ); $field['type'] = self::$_->array_get( $this->data_keys, "custom_field_type.{$type}", 'any' ); if ( isset( $field['options'] ) ) { $field['options'] = explode( "\n", $field['options'] ); $field['options'] = array_filter( $field['options'] ); } $fields[ $field_id ] = $field; } return $fields; } protected function _get_base_url() { $this->BASE_URL = str_replace( '@app_name@', $this->data[ self::$_data_keys['app_name'] ], $this->BASE_URL_PATTERN ); return $this->BASE_URL; } protected function _get_contact_by_email( $email ) { $params = array( $this->data[ self::$_data_keys['api_key'] ], 'Contact', 1, 0, array( 'Email' => $email ), array( 'Id', 'Groups' ) ); $data = self::$_->prepare_xmlrpc_method_call( 'DataService.query', $params ); $this->_do_request( $data ); if ( $this->response->ERROR ) { return false; } return self::$_->process_xmlrpc_response( $this->response->DATA ); } protected function _optin_email_address( $email ) { $params = array( $this->data[ self::$_data_keys['api_key'] ], $email, $this->SUBSCRIBED_VIA ); $data = self::$_->prepare_xmlrpc_method_call('APIEmailService.optIn', $params ); $this->_do_request( $data ); if ( $this->response->ERROR ) { return false; } return self::$_->process_xmlrpc_response( $this->response->DATA ); } protected function _process_custom_fields( $args ) { if ( ! isset( $args['custom_fields'] ) ) { return array(); } $fields = array(); foreach ( $args['custom_fields'] as $field_id => $value ) { if ( is_array( $value ) && $value ) { // This is a multiple choice field (eg. checkbox, radio, select) $value = array_values( $value ); $value = implode( ',', $value ); } $fields[ "_{$field_id}" ] = $value; } return $fields; } public function retrieve_subscribers_count() { $existing_lists = $this->data['lists']; if ( empty( $existing_lists ) ) { return; } foreach( $existing_lists as $list_id => $list_data ) { $params = array( $this->data[ self::$_data_keys['api_key'] ], 'Contact', array( 'Groups' => "%{$list_id}%" ) ); $data = self::$_->prepare_xmlrpc_method_call( 'DataService.count', $params ); $this->_do_request( $data ); if ( $this->response->ERROR ) { continue; } $subscribers_count = self::$_->process_xmlrpc_response( $this->response->DATA ); if ( empty( $subscribers_count ) || self::$_->is_xmlrpc_error( $subscribers_count ) ) { $subscribers_count = 0; } $existing_lists[ $list_id ]['subscribers_count'] = $subscribers_count; $this->data['lists'] = $existing_lists; $this->save_data(); } } /** * @inheritDoc */ protected function _process_subscriber_lists( $lists ) { $result = array(); if ( empty( $lists ) || ! is_array( $lists ) ) { return $result; } foreach( $lists as $list ) { $list_id = (string) $list->Id; $list_name = (string) $list->GroupName; $result[ $list_id ]['list_id'] = $list_id; $result[ $list_id ]['name'] = $list_name; $result[ $list_id ]['subscribers_count'] = 0; } return $result; } /** * @inheritDoc */ public function get_account_fields() { return array( self::$_data_keys['api_key'] => array( 'label' => esc_html__( 'API Key', 'et_core' ), ), self::$_data_keys['app_name'] => array( 'label' => esc_html__( 'App Name', 'et_core' ), ), ); } /** * @inheritDoc */ public function get_data_keymap( $keymap = array() ) { $keymap = array( 'subscriber' => array( 'name' => 'FirstName', 'last_name' => 'LastName', 'email' => 'Email', 'custom_fields' => 'custom_fields', ), 'custom_field' => array( 'field_id' => 'Name', 'name' => 'Label', 'type' => 'DataType', 'options' => 'Values', ), 'custom_field_type' => array( // Us => Them 'input' => 15, 'textarea' => 16, 'checkbox' => 17, 'radio' => 20, 'select' => 21, // Them => Us 15 => 'input', 16 => 'textarea', 17 => 'checkbox', 20 => 'radio', 21 => 'select', ), ); return parent::get_data_keymap( $keymap ); } /** * @inheritDoc */ public function fetch_subscriber_lists() { if ( empty( $this->data[ self::$_data_keys['api_key'] ] ) || empty( $this->data[ self::$_data_keys['app_name'] ] ) ) { return $this->API_KEY_REQUIRED; } $this->response_data_key = false; $params_count = array( $this->data[ self::$_data_keys['api_key'] ], 'ContactGroup', array( 'Id' => '%' ) ); $data_count = self::$_->prepare_xmlrpc_method_call( 'DataService.count', $params_count ); $this->_do_request( $data_count ); if ( $this->response->ERROR ) { return $this->response->ERROR_MESSAGE; } $records_count = (int) self::$_->process_xmlrpc_response( $this->http->response->DATA ); if ( 0 === $records_count ) { return 'success'; } // determine how many requests we need to retrieve all lists $number_of_additional_requests = floor( $records_count / 1000 ); $list_data = array(); for ( $i = 0; $i <= $number_of_additional_requests; $i++ ) { $params = array( $this->data[ self::$_data_keys['api_key'] ], 'ContactGroup', 1000, $i, array( 'Id' => '%' ), array( 'Id', 'GroupName' ) ); $data = self::$_->prepare_xmlrpc_method_call( 'DataService.query', $params ); $this->_do_request( $data ); if ( $this->http->response->ERROR ) { return $this->http->response->ERROR_MESSAGE; } $response = self::$_->process_xmlrpc_response( $this->http->response->DATA ); if ( self::$_->is_xmlrpc_error( $response ) ) { return $response->faultString; } $list_data = array_merge( $list_data, $response ); } $lists = $this->_process_subscriber_lists( $list_data ); if ( false === $lists ) { return $this->response->ERROR_MESSAGE; } else if ( self::$_->is_xmlrpc_error( $lists ) ) { return $lists->faultString; } $result = 'success'; $this->data['lists'] = $lists; $this->data['custom_fields'] = $this->_fetch_custom_fields(); $this->data['is_authorized'] = true; // retrieve counts right away if it can be done in reasonable time ( in 20 seconds ) if ( 20 >= count( $lists ) ) { $this->retrieve_subscribers_count(); } else { // estimate the time for all lists update assuming that one list can be updated in 1 second $estimated_time = ceil( count( $lists ) / 60 ); $result = array( 'need_counts_update' => true, 'message' => sprintf( esc_html__( 'Successfully authorized. Subscribers count will be updated in background, please check back in %1$s %2$s', 'et_core' ), $estimated_time, 1 === (int) $estimated_time ? esc_html__( 'minute', 'et_core' ) : esc_html__( 'minutes', 'et_core' ) ), ); } $this->save_data(); return $result; } /** * @inheritDoc */ public function subscribe( $args, $url = '' ) { if ( empty( $this->data[ self::$_data_keys['api_key'] ] ) || empty( $this->data[ self::$_data_keys['app_name'] ] ) ) { return $this->API_KEY_REQUIRED; } $message = ''; $search_result = $this->_get_contact_by_email( $args['email'] ); if ( false === $search_result ) { return $this->response->ERROR_MESSAGE; } else if ( self::$_->is_xmlrpc_error( $search_result ) ) { return $search_result->faultString; } if ( ! empty( $search_result ) ) { $message = esc_html__( 'Already subscribed', 'bloom' ); if ( false === strpos( $search_result[0]->Groups, $args['list_id'] ) ) { $result = $this->_add_contact_to_list( $search_result[0]->Id, $args['list_id'] ); $message = 'success'; if ( false === $result ) { return $this->response->ERROR_MESSAGE; } else if ( self::$_->is_xmlrpc_error( $result ) ) { return $result->faultString; } } } else { $custom_fields = $this->_process_custom_fields( $args ); $contact_details = array( 'FirstName' => $args['name'], 'LastName' => $args['last_name'], 'Email' => $args['email'], ); $new_contact_id = $this->_create_contact( array_merge( $contact_details, $custom_fields ) ); if ( false === $new_contact_id ) { return $this->response->ERROR_MESSAGE; } else if ( self::$_->is_xmlrpc_error( $new_contact_id ) ) { return $new_contact_id->faultString; } $result = $this->_add_contact_to_list( $new_contact_id, $args['list_id'] ); if ( false === $result ) { return $this->response->ERROR_MESSAGE; } else if ( self::$_->is_xmlrpc_error( $result ) ) { return $search_result->faultString; } if ( $this->_optin_email_address( $args['email'] ) ) { $message = 'success'; } } return ( '' !== $message ) ? $message : $this->FAILURE_MESSAGE; } } email/_ProviderName.php000064400000002712152214676150011111 0ustar00 array( 'list_id' => '', 'name' => '', 'subscribers_count' => '', ), 'subscriber' => array( 'name' => '', 'email' => '', 'list_id' => '', 'ip_address' => '', ), ); return parent::get_data_keymap( $keymap, $custom_fields_key ); } /** * @inheritDoc */ public function fetch_subscriber_lists() { // Implement get_subscriber_lists() method. } /** * @inheritDoc */ public function subscribe( $args, $url = '' ) { // Implement subscribe() method. } } email/_MailPoet3.php000064400000012565152214676150010322 0ustar00getSubscriberFields(); $processed = array(); foreach ( $fields as $field ) { $field_id = $field['id']; $field_name = $field['name']; if ( in_array( $field_id, array( 'email', 'first_name', 'last_name' ) ) ) { continue; } $processed[ $field_id ] = array( 'field_id' => $field_id, 'name' => $field_name, 'type' => 'any', ); } } return $processed; } protected function _process_custom_fields( $args ) { if ( ! isset( $args['custom_fields'] ) ) { return $args; } $custom_fields = $args['custom_fields']; $required_fields = $this->_get_required_custom_fields(); // Filter missing required custom field. $missing_fields = array_diff( $required_fields, array_keys( $custom_fields ) ); // Fill-up missing required custom fields with dummy content and merge with available ones. // This is required because of how MailPoet API validates the custom fields currently // and there's no filters available to alter this behavior right now. $fields = array_merge( $custom_fields, array_fill_keys( $missing_fields, 'n/a' ) ); unset( $args['custom_fields'] ); foreach ( $fields as $field_id => $value ) { if ( is_array( $value ) && $value ) { // This is a multiple choice field (eg. checkbox, radio, select) $value = array_keys( $value ); if ( count( $value ) > 1 ) { $value = implode( ',', $value ); } else { $value = array_pop( $value ); } } self::$_->array_set( $args, $field_id, $value ); } return $args; } /** * Get required custom fields. * * @return $required_fields */ protected function _get_required_custom_fields() { $fields = \MailPoet\API\API::MP( 'v1' )->getSubscriberFields(); $required_fields = []; foreach ( $fields as $field ) { // Custom field ids have `cf_` prefix. Also we need only the required ones. if ( false !== strpos( $field['id'], 'cf_' ) && $field['params']['required'] ) { $required_fields[] = $field['id']; } } return $required_fields; } /** * @inheritDoc */ public function get_account_fields() { return array(); } /** * @inheritDoc */ public function get_data_keymap( $keymap = array() ) { $keymap = array( 'list' => array( 'list_id' => 'id', 'name' => 'name', ), 'subscriber' => array( 'name' => 'first_name', 'last_name' => 'last_name', 'email' => 'email', 'custom_fields' => 'custom_fields', ), ); return parent::get_data_keymap( $keymap ); } /** * @inheritDoc */ public function fetch_subscriber_lists() { if ( ! class_exists( '\MailPoet\API\API' ) ) { return self::$PLUGIN_REQUIRED; } $data = \MailPoet\API\API::MP( 'v1' )->getLists(); if ( ! empty( $data ) ) { $this->data['lists'] = $this->_process_subscriber_lists( $data ); $list = is_array( $data ) ? array_shift( $data ) : array(); $this->data['custom_fields'] = $this->_fetch_custom_fields( '', $list ); } $this->data['is_authorized'] = true; $this->save_data(); return array( 'success' => $this->data ); } /** * @inheritDoc */ public function subscribe( $args, $url = '' ) { if ( ! class_exists( '\MailPoet\API\API' ) ) { ET_Core_Logger::error( self::$PLUGIN_REQUIRED ); return esc_html__( 'An error occurred. Please try again later.', 'et_core' ); } $subscriber = array(); $args = et_core_sanitized_previously( $args ); $subscriber_data = $this->transform_data_to_provider_format( $args, 'subscriber' ); $subscriber_data = $this->_process_custom_fields( $subscriber_data ); $subscriber_data = self::$_->array_flatten( $subscriber_data ); $result = 'success'; $lists = array( $args['list_id'] ); unset( $subscriber_data['custom_fields'] ); /** * Check if the subscriber with this email already exists. */ try { $subscriber = \MailPoet\API\API::MP( 'v1' )->getSubscriber( $subscriber_data['email'] ); } catch ( \Exception $e ) { $subscriber = array(); } /** * If subscriber is not found, add as a new subscriber. Otherwise, add existing subscriber to the lists. */ if ( empty( $subscriber ) ) { try { \MailPoet\API\API::MP( 'v1' )->addSubscriber( $subscriber_data, $lists ); } catch ( Exception $exception ) { $result = $exception->getMessage(); } } else { try { \MailPoet\API\API::MP( 'v1' )->subscribeToLists( $subscriber['id'], $lists ); } catch ( Exception $exception ) { $result = $exception->getMessage(); } } return $result; } } email/Provider.php000064400000025175152214676150010161 0ustar00service_type = 'email'; parent::__construct( $owner, $account_name, $api_key ); if ( 'builder' === $this->owner ) { $owner = 'Divi Builder'; } else { $owner = ucfirst( $this->owner ); } $this->SUBSCRIBED_VIA = sprintf( '%1$s %2$s.', esc_html__( 'Subscribed via', 'et_core' ), $owner ); /** * Filters the max number of results returned from email API provider per request. * * @since 3.17.2 * * @param int $max_results_count */ $this->COUNT = apply_filters( 'et_core_api_email_max_results_count', 250 ); } /** * Get custom fields for a subscriber list. * * @param int|string $list_id * @param array $list * * @return array */ protected function _fetch_custom_fields( $list_id = '', $list = array() ) { if ( 'dynamic' === $this->custom_fields ) { return array(); } if ( null === $this->request || $this->request->COMPLETE ) { $this->prepare_request( $this->FIELDS_URL ); } $this->make_remote_request(); $result = array(); if ( false !== $this->response_data_key && empty( $this->response_data_key ) ) { // Let child class handle parsing the response data themselves. return $result; } if ( $this->response->ERROR ) { et_debug( $this->get_error_message() ); return $result; } if ( false === $this->response_data_key ) { // The data returned by the service is not nested. $data = $this->response->DATA; } else { // The data returned by the service is nested under a single key. $data = $this->response->DATA[ $this->response_data_key ]; } foreach ( $data as &$custom_field ) { $custom_field = $this->transform_data_to_our_format( $custom_field, 'custom_field' ); } $fields = array(); $field_types = self::$_->array_get( $this->data_keys, 'custom_field_type' ); foreach ( $data as $field ) { $field_id = $field['field_id']; $type = self::$_->array_get( $field, 'type', 'any' ); if ( $field_types && ! isset( $field_types[ $type ] ) ) { // Unsupported field type. Make it 'text' instead. $type = 'text'; } if ( isset( $field['hidden'] ) && is_string( $field['hidden'] ) ) { $field['hidden'] = 'false' === $field['hidden'] ? false : true; } $field['type'] = self::$_->array_get( $this->data_keys, "custom_field_type.{$type}", 'any' ); $fields[ $field_id ] = $field; } return $fields; } /** * @inheritDoc */ protected function _get_data() { $options = parent::_get_data(); // return empty array in case of empty name if ( '' === $this->account_name || ! is_string( $this->account_name ) ) { return array(); } $provider = sanitize_text_field( $this->slug ); $account = sanitize_text_field( $this->account_name ); if ( ! isset( $options['accounts'][ $provider ][ $account ] ) ) { $options['accounts'][ $provider ][ $account ] = array(); update_option( "et_core_api_email_options", $options ); } return $options['accounts'][ $provider ][ $account ]; } protected function _process_custom_fields( $args ) { return $args; } /** * Processes subscriber lists data from the provider's API and returns only the data we're interested in. * * @since 1.1.0 * * @param array $lists Subscriber lists data to process. * * @return array */ protected function _process_subscriber_lists( $lists ) { $id_key = $this->data_keys['list']['list_id']; $result = array(); foreach ( (array) $lists as $list ) { if ( ! is_array( $list ) ) { $list = (array) $list; } if ( ! isset( $list[ $id_key ] ) ) { continue; } $id = $list[ $id_key ]; $result[ $id ] = $this->transform_data_to_our_format( $list, 'list' ); if ( ! array_key_exists( 'subscribers_count', $result[ $id ] ) ) { $result[ $id ]['subscribers_count'] = 0; } $get_custom_fields = $this->custom_fields && 'list' === $this->custom_fields_scope; if ( $get_custom_fields && $custom_fields = $this->_fetch_custom_fields( $id, $list ) ) { $result[ $id ]['custom_fields'] = $custom_fields; } } return $result; } /** * Returns whether or not an account exists in the database. * * @param string $provider * @param string $account_name * * @return bool */ public static function account_exists( $provider, $account_name ) { $all_accounts = self::get_accounts(); return isset( $all_accounts[ $provider ][ $account_name ] ); } /** * @inheritDoc */ public function delete() { self::remove_account( $this->slug, $this->account_name ); $this->account_name = ''; $this->_get_data(); } /** * Retrieves the email accounts data from the database. * * @return array */ public static function get_accounts() { $options = (array) get_option( 'et_core_api_email_options' ); return isset( $options['accounts'] ) ? $options['accounts'] : array(); } /** * @inheritDoc */ public function get_data_keymap( $keymap = array() ) { return $keymap; } /** * Retrieves the subscriber lists for the account assigned to the current instance. * * @return string 'success' if successful, an error message otherwise. */ public function fetch_subscriber_lists() { if ( null === $this->request || $this->request->COMPLETE ) { $this->prepare_request( $this->LISTS_URL ); } $this->make_remote_request(); $result = 'success'; if ( false !== $this->response_data_key && empty( $this->response_data_key ) ) { // Let child class handle parsing the response data themselves. return ''; } if ( $this->response->ERROR ) { return $this->get_error_message(); } if ( false === $this->response_data_key ) { // The data returned by the service is not nested. $data = $this->response->DATA; } else { // The data returned by the service is nested under a single key. $data = $this->response->DATA[ $this->response_data_key ]; } if ( ! empty( $data ) ) { $this->data['lists'] = $this->_process_subscriber_lists( $data ); $this->data['is_authorized'] = true; $list = is_array( $data ) ? array_shift( $data ) : array(); if ( $this->custom_fields && 'account' === $this->custom_fields_scope ) { $this->data['custom_fields'] = $this->_fetch_custom_fields( '', $list ); } $this->save_data(); } return $result; } /** * Remove an account * * @param $provider * @param $account_name */ public static function remove_account( $provider, $account_name ) { $options = (array) get_option( 'et_core_api_email_options' ); unset( $options['accounts'][ $provider ][ $account_name ] ); update_option( 'et_core_api_email_options', $options ); } /** * @inheritDoc */ public function save_data() { self::update_account( $this->slug, $this->account_name, $this->data ); } /** * @inheritDoc */ public function set_account_name( $name ) { $this->account_name = $name; $this->data = $this->_get_data(); } /** * Makes an HTTP POST request to add a subscriber to a list. * * @param string[] $args Data for the POST request. * @param string $url The URL for the POST request. Optional when called on child classes. * * @return string 'success' if successful, an error message otherwise. */ public function subscribe( $args, $url = '' ) { if ( null === $this->request || $this->request->COMPLETE ) { if ( ! in_array( 'ip_address', $args ) || 'true' === $args['ip_address'] ) { $args['ip_address'] = et_core_get_ip_address(); } else if ( 'false' === $args['ip_address'] ) { $args['ip_address'] = '0.0.0.0'; } $args = $this->transform_data_to_provider_format( $args, 'subscriber' ); if ( $this->custom_fields ) { $args = $this->_process_custom_fields( $args ); } $this->prepare_request( $url, 'POST', false, $args ); } else if ( $this->request->JSON_BODY && ! is_string( $this->request->BODY ) && ! $this->uses_oauth ) { $this->request->BODY = json_encode( $this->request->BODY ); } else if ( is_array( $this->request->BODY ) ) { $this->request->BODY = array_merge( $this->request->BODY, $args ); } else if ( ! $this->request->JSON_BODY ) { $this->request->BODY = $args; } $this->make_remote_request(); return $this->response->ERROR ? $this->get_error_message() : 'success'; } /** * Updates the data for a provider account. * * @param string $provider The provider's slug. * @param string $account The account name. * @param array $data The new data for the account. */ public static function update_account( $provider, $account, $data ) { $options = (array) get_option( 'et_core_api_email_options' ); $existing_data = array(); if ( empty( $account ) || empty( $provider ) ) { return; } $provider = sanitize_text_field( $provider ); $account = sanitize_text_field( $account ); if ( isset( $options['accounts'][ $provider ][ $account ] ) ) { $existing_data = $options['accounts'][ $provider ][ $account ]; } $options['accounts'][ $provider ][ $account ] = array_merge( $existing_data, $data ); update_option( 'et_core_api_email_options', $options ); } } email/Providers.php000064400000022552152214676150010340 0ustar00_initialize(); } } protected function _initialize() { self::$_ = ET_Core_Data_Utils::instance(); self::$_metadata = et_core_get_components_metadata(); $third_party_providers = et_core_get_third_party_components( 'api/email' ); $load_fields = is_admin() || et_core_is_saving_builder_modules_cache() || et_core_is_fb_enabled() || isset( $_GET['et_fb'] ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification $all_names = array( 'official' => self::$_metadata['groups']['api/email']['members'], 'third-party' => array_keys( $third_party_providers ), ); $_names_by_slug = array(); $_custom_fields_support = array( 'dynamic' => array(), 'predefined' => array(), 'none' => array() ); $_any_custom_field_type = array(); foreach ( $all_names as $provider_type => $provider_names ) { $_names_by_slug[ $provider_type ] = array(); foreach ( $provider_names as $provider_name ) { if ( 'Fields' === $provider_name || self::$_->includes( $provider_name, 'Provider' ) ) { continue; } if ( 'official' === $provider_type ) { $class_name = self::$_metadata[ $provider_name ]; $provider_slug = self::$_metadata[ $class_name ]['slug']; $provider = $load_fields ? new $class_name( 'ET_Core', '' ) : null; } else { $provider = $third_party_providers[ $provider_name ]; $provider_slug = is_object( $provider ) ? $provider->slug : ''; } if ( ! $provider_slug ) { continue; } $_names_by_slug[ $provider_type ][ $provider_slug ] = $provider_name; if ( $load_fields && is_object( $provider ) ) { self::$_fields[ $provider_slug ] = $provider->get_account_fields(); if ( $scope = $provider->custom_fields ) { $_custom_fields_support[ $scope ][ $provider_slug ] = $provider_name; if ( ! self::$_->array_get( $provider->data_keys, 'custom_field_type' ) ) { $_any_custom_field_type[] = $provider_slug; } } else { $_custom_fields_support['none'][ $provider_slug ] = $provider_name; } } } } /** * Filters the enabled email providers. * * @param array[] { * * @type string[] $provider_type { * * @type string $slug Provider name * } * } */ self::$_names_by_slug = apply_filters( 'et_core_api_email_enabled_providers', $_names_by_slug ); foreach ( array_keys( $all_names ) as $provider_type ) { self::$_names[ $provider_type ] = array_values( self::$_names_by_slug[ $provider_type ] ); self::$_slugs[ $provider_type ] = array_keys( self::$_names_by_slug[ $provider_type ] ); } self::$_name_field_only = self::$_metadata['groups']['api/email']['name_field_only']; self::$_custom_fields_support = $_custom_fields_support; self::$_any_custom_field_type = $_any_custom_field_type; } /** * Returns the email provider accounts array from core. * * @return array|mixed */ public function accounts() { return ET_Core_API_Email_Provider::get_accounts(); } /** * @see {@link \ET_Core_API_Email_Provider::account_exists()} */ public function account_exists( $provider, $account_name ) { return ET_Core_API_Email_Provider::account_exists( $provider, $account_name ); } public function account_fields( $provider = 'all' ) { if ( 'all' !== $provider ) { return isset( self::$_fields[ $provider ] ) ? self::$_fields[ $provider ] : array(); } return self::$_fields; } public function custom_fields_data() { $enabled_providers = self::slugs(); $custom_fields_data = array(); foreach ( $this->accounts() as $provider_slug => $accounts ) { if ( ! in_array( $provider_slug, $enabled_providers ) ) { continue; } foreach ( $accounts as $account_name => $account_details ) { if ( empty( $account_details['lists'] ) ) { continue; } if ( ! empty( $account_details['custom_fields'] ) ) { $custom_fields_data[$provider_slug][$account_name]['custom_fields'] = $account_details['custom_fields']; continue; } foreach ( (array) $account_details['lists'] as $list_id => $list_details ) { if ( ! empty( $list_details['custom_fields'] ) ) { $custom_fields_data[$provider_slug][$account_name][$list_id] = $list_details['custom_fields']; } } } } return $custom_fields_data; } /** * Get class instance for a provider. Instance will be created if necessary. * * @param string $name_or_slug The provider's name or slug. * @param string $account_name The identifier for the desired account with the provider. * @param string $owner The owner for the instance. * * @return bool|ET_Core_API_Email_Provider The provider instance or `false` if not found. */ public function get( $name_or_slug, $account_name, $owner = 'ET_Core' ) { $name_or_slug = str_replace( ' ', '', $name_or_slug ); $is_official = isset( self::$_metadata[ $name_or_slug ] ); if ( ! $is_official && ! $this->is_third_party( $name_or_slug ) ) { return false; } if ( ! in_array( $name_or_slug, array_merge( self::names(), self::slugs() ) ) ) { return false; } // Make sure we have the component name if ( $is_official ) { $class_name = self::$_metadata[ $name_or_slug ]; $name = self::$_metadata[ $class_name ]['name']; } else { $components = et_core_get_third_party_components( 'api/email' ); if ( ! $name = array_search( $name_or_slug, self::$_names_by_slug['third-party'] ) ) { $name = $name_or_slug; } } if ( ! isset( self::$providers[ $name ][ $owner ] ) ) { self::$providers[ $name ][ $owner ] = $is_official ? new $class_name( $owner, $account_name ) : $components[ $name ]; } return self::$providers[ $name ][ $owner ]; } public static function instance() { if ( null === self::$_instance ) { self::$_instance = new self; } return self::$_instance; } public function is_third_party( $name_or_slug ) { $is_third_party = in_array( $name_or_slug, self::$_names['third-party'] ); return $is_third_party ? $is_third_party : in_array( $name_or_slug, self::$_slugs['third-party'] ); } /** * Returns the names of available providers. List can optionally be filtered. * * @param string $type The component type to include ('official'|'third-party'|'all'). Default is 'all'. * * @return array */ public function names( $type = 'all' ) { if ( 'all' === $type ) { $names = array_merge( self::$_names['third-party'], self::$_names['official'] ); } else { $names = self::$_names[ $type ]; } return $names; } /** * Returns an array mapping the slugs of available providers to their names. List can optionally be filtered. * * @param string $type The component type to include ('official'|'third-party'|'all'). Default is 'all'. * @param string $filter Optionally filter the list by a condition. * Accepts 'name_field_only', 'predefined_custom_fields', 'dynamic_custom_fields', * 'no_custom_fields', 'any_custom_field_type', 'custom_fields'. * * @return array */ public function names_by_slug( $type = 'all', $filter = '' ) { if ( 'all' === $type ) { $names_by_slug = array_merge( self::$_names_by_slug['third-party'], self::$_names_by_slug['official'] ); } else { $names_by_slug = self::$_names_by_slug[ $type ]; } if ( 'name_field_only' === $filter ) { $names_by_slug = self::$_name_field_only; } else if ( 'predefined_custom_fields' === $filter ) { $names_by_slug = self::$_custom_fields_support['predefined']; } else if ( 'dynamic_custom_fields' === $filter ) { $names_by_slug = self::$_custom_fields_support['dynamic']; } else if ( 'no_custom_fields' === $filter ) { $names_by_slug = self::$_custom_fields_support['none']; } else if ( 'any_custom_field_type' === $filter ) { $names_by_slug = self::$_any_custom_field_type; } else if ( 'custom_fields' === $filter ) { $names_by_slug = array_merge( self::$_custom_fields_support['predefined'], self::$_custom_fields_support['dynamic'] ); } return $names_by_slug; } /** * @see {@link \ET_Core_API_Email_Provider::remove_account()} */ public function remove_account( $provider, $account_name ) { ET_Core_API_Email_Provider::remove_account( $provider, $account_name ); } /** * Returns the slugs of available providers. List can optionally be filtered. * * @param string $type The component type to include ('official'|'third-party'|'all'). Default is 'all'. * * @return array */ public function slugs( $type = 'all' ) { if ( 'all' === $type ) { $names = array_merge( self::$_slugs['third-party'], self::$_slugs['official'] ); } else { $names = self::$_slugs[ $type ]; } return $names; } /** * @see {@link \ET_Core_API_Email_Provider::update_account()} */ public function update_account( $provider, $account, $data ) { ET_Core_API_Email_Provider::update_account( $provider, $account, $data ); } } email/Emma.php000064400000007333152214676150007242 0ustar00 'api_key', 'password' => 'private_api_key', ); /** * @inheritDoc */ public $name = 'Emma'; /** * @inheritDoc */ public $slug = 'emma'; protected function _fetch_custom_fields( $list_id = '', $list = array() ) { $this->response_data_key = false; $this->prepare_request( $this->_get_custom_fields_url() ); return parent::_fetch_custom_fields( $list_id, $list ); } protected function _get_custom_fields_url() { return "https://api.e2ma.net/{$this->data['user_id']}/fields?group_types=all"; } protected function _get_lists_url() { return "https://api.e2ma.net/{$this->data['user_id']}/groups?group_types=all"; } protected function _get_subscribe_url() { return "https://api.e2ma.net/{$this->data['user_id']}/members/signup"; } protected function _process_custom_fields( $args ) { if ( ! isset( $args['custom_fields'] ) ) { return $args; } $fields = $args['custom_fields']; unset( $args['custom_fields'] ); foreach ( $fields as $field_id => $value ) { if ( is_array( $value ) && $value ) { // This is a multiple choice field (eg. checkbox, radio, select) $value = array_values( $value ); } self::$_->array_set( $args, "fields.{$field_id}", $value ); } return $args; } /** * @inheritDoc */ public function get_account_fields() { return array( 'api_key' => array( 'label' => esc_html__( 'Public API Key', 'et_core' ), ), 'private_api_key' => array( 'label' => esc_html__( 'Private API Key', 'et_core' ), ), 'user_id' => array( 'label' => esc_html__( 'Account ID', 'et_core' ), ), ); } /** * @inheritDoc */ public function get_data_keymap( $keymap = array() ) { $keymap = array( 'list' => array( 'name' => 'group_name', 'list_id' => 'member_group_id', 'subscribers_count' => 'active_count', ), 'subscriber' => array( 'email' => 'email', 'name' => 'fields.first_name', 'last_name' => 'fields.last_name', 'list_id' => '@group_ids', 'custom_fields' => 'custom_fields', ), 'custom_field' => array( 'field_id' => 'shortcut_name', 'name' => 'display_name', 'options' => 'options', 'type' => 'widget_type', ), 'custom_field_type' => array( // Us <=> Them 'radio' => 'radio', // Us => Them 'select' => 'select one', 'text' => 'long', 'checkbox' => 'check_multiple', // Them => Us 'text' => 'input', 'long' => 'text', 'check_multiple' => 'checkbox', 'select one' => 'select', ), ); return parent::get_data_keymap( $keymap ); } /** * @inheritDoc */ public function fetch_subscriber_lists() { if ( empty( $this->data['api_key'] ) ) { return $this->API_KEY_REQUIRED; } $this->LISTS_URL = $this->_get_lists_url(); $this->response_data_key = false; return parent::fetch_subscriber_lists(); } /** * @inheritDoc */ public function subscribe( $args, $url = '' ) { $url = $this->_get_subscribe_url(); $this->response_data_key = 'member_id'; $args = $this->transform_data_to_provider_format( $args, 'subscriber' ); $args = $this->_process_custom_fields( $args ); $this->prepare_request( $url, 'POST', false, $args, true ); return parent::subscribe( $args, $url ); } } email/_MailPoet2.php000064400000007735152214676150010324 0ustar00 array( 'list_id' => 'id', 'name' => 'name', ), 'subscriber' => array( 'name' => 'first_name', 'last_name' => 'last_name', 'email' => 'email', ), ); return parent::get_data_keymap( $keymap ); } /** * @inheritDoc */ public function fetch_subscriber_lists() { if ( ! class_exists( 'WYSIJA' ) ) { return self::$PLUGIN_REQUIRED; } $lists = array(); $list_model = WYSIJA::get( 'list', 'model' ); $all_lists_array = $list_model->get( array( 'name', 'list_id' ), array( 'is_enabled' => '1' ) ); foreach ( $all_lists_array as $list_details ) { $lists[ $list_details['list_id'] ]['name'] = sanitize_text_field( $list_details['name'] ); $user_model = WYSIJA::get( 'user_list', 'model' ); $all_subscribers_array = $user_model->get( array( 'user_id' ), array( 'list_id' => $list_details['list_id'] ) ); $subscribers_count = count( $all_subscribers_array ); $lists[ $list_details['list_id'] ]['subscribers_count'] = sanitize_text_field( $subscribers_count ); } $this->data['is_authorized'] = true; if ( ! empty( $lists ) ) { $this->data['lists'] = $lists; } $this->save_data(); return array( 'success' => $this->data ); } /** * @inheritDoc */ public function subscribe( $args, $url = '' ) { if ( ! class_exists( 'WYSIJA' ) ) { ET_Core_Logger::error( self::$PLUGIN_REQUIRED ); return esc_html__( 'An error occurred. Please try again later.', 'et_core' ); } global $wpdb; $wpdb->wysija_user_table = $wpdb->prefix . 'wysija_user'; $wpdb->wysija_user_lists_table = $wpdb->prefix . 'wysija_user_list'; // get the ID of subscriber if they're in the list already $subscriber_id = $wpdb->get_var( $wpdb->prepare( "SELECT user_id FROM {$wpdb->wysija_user_table} WHERE email = %s", array( et_core_sanitized_previously( $args['email'] ), ) ) ); $already_subscribed = 0; // if current email is subscribed, then check whether it subscribed to the current list if ( ! empty( $subscriber_id ) ) { $already_subscribed = (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM {$wpdb->wysija_user_lists_table} WHERE user_id = %s AND list_id = %s", array( $subscriber_id, et_core_sanitized_previously( $args['list_id'] ), ) ) ); } unset( $wpdb->wysija_user_table ); unset( $wpdb->wysija_user_list_table ); // if email is not subscribed to current list, then subscribe. if ( 0 === $already_subscribed ) { $new_user = array( 'user' => array( 'email' => et_core_sanitized_previously( $args['email'] ), 'firstname' => et_core_sanitized_previously( $args['name'] ), 'lastname' => et_core_sanitized_previously( $args['last_name'] ), ), 'user_list' => array( 'list_ids' => array( et_core_sanitized_previously( $args['list_id'] ) ), ), ); $mailpoet_class = WYSIJA::get( 'user', 'helper' ); $error_message = $mailpoet_class->addSubscriber( $new_user ); $error_message = is_int( $error_message ) ? 'success' : $error_message; } else { $error_message = esc_html__( 'Already Subscribed', 'bloom' ); } return $error_message; } } email/Aweber.php000064400000013603152214676150007565 0ustar00accounts_url = "{$this->BASE_URL}/accounts"; } protected function _fetch_custom_fields( $list_id = '', $list = array() ) { $this->prepare_request( $list['custom_fields_collection_link'] ); return parent::_fetch_custom_fields( $list_id, $list ); } protected function _get_lists_collection_url() { $this->prepare_request( $this->accounts_url ); $this->make_remote_request(); $url = ''; if ( ! $this->response->ERROR && ! empty( $this->response->DATA['entries'][0]['lists_collection_link'] ) ) { $url = $this->response->DATA['entries'][0]['lists_collection_link']; } return $url; } protected static function _parse_ID( $ID ) { $values = explode( '|', $ID ); return ( count( $values ) === 6 ) ? $values : null; } protected function _process_custom_fields( $args ) { if ( ! isset( $args['custom_fields'] ) ) { return $args; } $fields = $args['custom_fields']; unset( $args['custom_fields'] ); foreach ( $fields as $field_id => $value ) { if ( is_array( $value ) && $value ) { // This is a multiple choice field (eg. checkbox, radio, select) $value = array_values( $value ); if ( count( $value ) > 1 ) { $value = implode( ',', $value ); } else { $value = array_pop( $value ); } } $list_id = $args['list_id']; $field_name = self::$_->array_get( $this->data, "lists.{$list_id}.custom_fields.{$field_id}.name" ); self::$_->array_set( $args, "custom_fields.{$field_name}", $value ); } return $args; } /** * Uses the app's authorization code to get an access token */ public function authenticate() { if ( empty( $this->data['api_key'] ) ) { return false; } $key_parts = self::_parse_ID( $this->data['api_key'] ); if ( null === $key_parts ) { return false; } list( $consumer_key, $consumer_secret, $request_token, $request_secret, $verifier ) = $key_parts; if ( ! $verifier ) { return false; } $this->data['consumer_key'] = $consumer_key; $this->data['consumer_secret'] = $consumer_secret; $this->data['access_key'] = $request_token; $this->data['access_secret'] = $request_secret; $this->oauth_verifier = $verifier; // AWeber returns oauth access key in url query format :face_with_rolling_eyes: $this->http->expects_json = false; return parent::authenticate(); } /** * @inheritDoc */ public function get_account_fields() { return array( 'api_key' => array( 'label' => esc_html__( 'Authorization Code', 'et_core' ), ), ); } /** * @inheritDoc */ public function get_error_message() { $error_message = parent::get_error_message(); return preg_replace('/https.*/m', '', $error_message ); } /** * @inheritDoc */ public function get_data_keymap( $keymap = array() ) { $keymap = array( 'list' => array( 'list_id' => 'id', 'name' => 'name', 'subscribers_count' => 'total_subscribers', ), 'subscriber' => array( 'name' => 'name', 'email' => 'email', 'ad_tracking' => 'ad_tracking', 'custom_fields' => 'custom_fields', ), 'error' => array( 'error_message' => 'error.message', ), 'custom_field' => array( 'field_id' => 'id', 'name' => 'name', ), ); return parent::get_data_keymap( $keymap ); } /** * @inheritDoc */ public function fetch_subscriber_lists() { $needs_to_authenticate = ! $this->is_authenticated() || ! $this->_initialize_oauth_helper(); if ( $needs_to_authenticate && ! $this->authenticate() ) { if ( empty( $this->response->DATA ) ) { return ''; } $this->response->DATA = json_decode( $this->response->DATA, true ); return $this->get_error_message(); } $this->http->expects_json = true; $this->LISTS_URL = $this->_get_lists_collection_url(); if ( empty( $this->LISTS_URL ) ) { return ''; } $this->response_data_key = 'entries'; return parent::fetch_subscriber_lists(); } /** * @inheritDoc */ public function subscribe( $args, $url = '' ) { $lists_url = $this->_get_lists_collection_url(); $url = "{$lists_url}/{$args['list_id']}/subscribers"; $ip_address = 'true' === self::$_->array_get( $args, 'ip_address', 'true' ); $params = $this->_process_custom_fields( $args ); $params = $this->transform_data_to_provider_format( $params, 'subscriber' ); $params = array_merge( $params, array( 'ws.op' => 'create', 'ip_address' => $ip_address ? et_core_get_ip_address() : '0.0.0.0', 'misc_notes' => $this->SUBSCRIBED_VIA, ) ); // There is a bug in AWeber some characters not encoded properly on AWeber side when sending data in x-www-form-urlencoded format so use json instead $this->prepare_request( $url, 'POST', false, $params, true ); $this->request->HEADERS['Content-Type'] = 'application/json'; return parent::subscribe( $params, $url ); } } email/GetResponse.php000064400000010064152214676150010614 0ustar00_maybe_set_custom_headers(); } protected function _maybe_set_custom_headers() { if ( empty( $this->custom_headers ) && isset( $this->data['api_key'] ) ) { $this->custom_headers = array( 'X-Auth-Token' => "api-key {$this->data['api_key']}" ); } } protected function _process_custom_fields( $args ) { if ( ! isset( $args['custom_fields'] ) ) { return $args; } $fields_unprocessed = $args['custom_fields']; $fields = array(); unset( $args['custom_fields'] ); foreach ( $fields_unprocessed as $field_id => $value ) { if ( is_array( $value ) && $value ) { // This is a multiple choice field (eg. checkbox, radio, select) $value = array_values( $value ); } else { $value = array( $value ); } $fields[] = array( 'customFieldId' => $field_id, 'value' => $value, ); } $args['customFieldValues'] = $fields; return $args; } /** * @inheritDoc */ public function get_account_fields() { return array( 'api_key' => array( 'label' => esc_html__( 'API Key', 'et_core' ), ), ); } /** * @inheritDoc */ public function get_data_keymap( $keymap = array() ) { $keymap = array( 'list' => array( 'name' => 'name', 'list_id' => 'campaignId', 'subscribers_count' => 'totalSubscribers', ), 'subscriber' => array( 'name' => 'name', 'email' => 'email', 'list_id' => 'campaign.campaignId', 'ip_address' => 'ipAddress', 'custom_fields' => 'custom_fields', ), 'error' => array( 'error_message' => 'message', ), 'custom_field' => array( 'field_id' => 'customFieldId', 'name' => 'name', 'type' => 'fieldType', 'options' => 'values', 'hidden' => 'hidden', ), 'custom_field_type' => array( // Us <=> Them 'textarea' => 'textarea', 'radio' => 'radio', 'checkbox' => 'checkbox', // Us => Them 'input' => 'text', 'select' => 'single_select', // Them => Us 'text' => 'input', 'single_select' => 'select', ), ); return parent::get_data_keymap( $keymap ); } /** * @inheritDoc */ public function fetch_subscriber_lists() { if ( empty( $this->data['api_key'] ) ) { return $this->API_KEY_REQUIRED; } $this->_maybe_set_custom_headers(); $this->response_data_key = false; return parent::fetch_subscriber_lists(); } /** * @inheritDoc */ public function subscribe( $args, $url = '' ) { $ip_address = 'true' === self::$_->array_get( $args, 'ip_address', 'true' ) ? et_core_get_ip_address() : '0.0.0.0'; $args['ip_address'] = $ip_address; $args = $this->transform_data_to_provider_format( $args, 'subscriber' ); $args = $this->_process_custom_fields( $args ); $args['note'] = $this->SUBSCRIBED_VIA; $args['dayOfCycle'] = 0; if ( empty( $args['name'] ) ) { unset( $args['name'] ); } $this->prepare_request( $this->SUBSCRIBE_URL, 'POST', false, $args ); return parent::subscribe( $args, $this->SUBSCRIBE_URL ); } } email/MailPoet.php000064400000005160152214676150010071 0ustar00=' ); if ( $has_php53 && class_exists( '\MailPoet\API\API' ) ) { require_once( ET_CORE_PATH . 'components/api/email/_MailPoet3.php' ); $this->_init_provider_class( '3', $owner, $account_name, $api_key ); } else if ( class_exists( 'WYSIJA' ) ) { require_once( ET_CORE_PATH . 'components/api/email/_MailPoet2.php' ); $this->_init_provider_class( '2', $owner, $account_name, $api_key ); } } /** * Initiate provider class based on the version number. * * @param string $version Version number. * @param string $owner Owner. * @param string $account_name Account name. * @param string $api_key API key. */ protected function _init_provider_class( $version, $owner, $account_name, $api_key ) { if ( '3' === $version ) { $this->_MP = new ET_Core_API_Email_MailPoet3( $owner, $account_name, $api_key ); } else { $this->_MP = new ET_Core_API_Email_MailPoet2( $owner, $account_name, $api_key ); $this->custom_fields = false; } } /** * @inheritDoc */ public function get_account_fields() { return array(); } /** * @inheritDoc */ public function get_data_keymap( $keymap = array() ) { if ( $this->_MP ) { return $this->_MP->get_data_keymap( $keymap ); } return parent::get_data_keymap( $keymap ); } /** * @inheritDoc */ public function fetch_subscriber_lists() { $lists_data = $this->_MP ? $this->_MP->fetch_subscriber_lists() : self::$PLUGIN_REQUIRED; // Update data in Main MailPoet class, so correct lists data can be accessed if ( isset( $lists_data['success'] ) ) { $this->data = $lists_data['success']; $this->save_data(); return 'success'; } return $lists_data; } /** * @inheritDoc */ public function subscribe( $args, $url = '' ) { return $this->_MP ? $this->_MP->subscribe( $args, $url ) : self::$PLUGIN_REQUIRED; } } email/CampaignMonitor.php000064400000014355152214676150011454 0ustar00 'api_key', 'password' => '-', ); /** * @inheritDoc */ public $name = 'CampaignMonitor'; /** * @inheritDoc */ public $name_field_only = true; /** * @inheritDoc */ public $slug = 'campaign_monitor'; /** * @inheritDoc * @internal If true, oauth endpoints properties must also be defined. */ public $uses_oauth = false; public function __construct( $owner, $account_name, $api_key = '' ) { parent::__construct( $owner, $account_name, $api_key ); $this->http_auth['password'] = $owner; } protected function _fetch_custom_fields( $list_id = '', $list = array() ) { $this->prepare_request( "{$this->BASE_URL}/lists/{$list_id}/customfields.json" ); $this->make_remote_request(); $result = array(); if ( $this->response->ERROR ) { et_debug( $this->get_error_message() ); return $result; } foreach ( $this->response->DATA as &$custom_field ) { $custom_field = $this->transform_data_to_our_format( $custom_field, 'custom_field' ); $custom_field['field_id'] = ltrim( rtrim( $custom_field['field_id'], ']' ), '[' ); } $fields = array(); foreach ( $this->response->DATA as $field ) { $field_id = $field['field_id']; $type = self::$_->array_get( $field, 'type', 'any' ); $field['type'] = self::$_->array_get( $this->data_keys, "custom_field_type.{$type}", 'any' ); $fields[ $field_id ] = $field; } return $fields; } protected function _get_clients() { $url = "{$this->BASE_URL}/clients.json"; $this->prepare_request( $url ); $this->make_remote_request(); if ( $this->response->ERROR ) { return $this->get_error_message(); } return (array) $this->response->DATA; } protected function _get_subscriber_counts() { $subscriber_lists = $this->_process_subscriber_lists( $this->response->DATA ); $with_counts = array(); foreach ( $subscriber_lists as $subscriber_list ) { $list_id = $subscriber_list['list_id']; $with_counts[ $list_id ] = $subscriber_list; $url = "{$this->BASE_URL}/lists/{$list_id}/stats.json"; $this->prepare_request( $url ); $this->make_remote_request(); if ( $this->response->ERROR ) { continue; } if ( isset( $this->response->DATA['TotalActiveSubscribers'] ) ) { $with_counts[ $list_id ]['subscribers_count'] = $this->response->DATA['TotalActiveSubscribers']; } else { $with_counts[ $list_id ]['subscribers_count'] = 0; } usleep( 500000 ); // 0.5 seconds } return $with_counts; } protected function _process_custom_fields( $args ) { if ( ! isset( $args['custom_fields'] ) ) { return $args; } $fields_unprocessed = $args['custom_fields']; unset( $args['custom_fields'] ); $fields = array(); foreach ( $fields_unprocessed as $field_id => $value ) { if ( is_array( $value ) && $value ) { // This is a multiple choice field (eg. checkbox) foreach ( $value as $selected_option ) { $fields[] = array( 'Key' => $field_id, 'Value' => $selected_option, ); } } else { $fields[] = array( 'Key' => $field_id, 'Value' => $value, ); } } $args['CustomFields'] = $fields; return $args; } /** * @inheritDoc */ public function get_account_fields() { return array( 'api_key' => array( 'label' => esc_html__( 'API Key', 'et_core' ), ), ); } /** * @inheritDoc */ public function get_data_keymap( $keymap = array() ) { $keymap = array( 'list' => array( 'list_id' => 'ListID', 'name' => 'Name', 'subscribers_count' => 'TotalActiveSubscribers', ), 'subscriber' => array( 'name' => 'Name', 'email' => 'EmailAddress', 'custom_fields' => 'custom_fields', ), 'error' => array( 'error_message' => 'Message', ), 'custom_field' => array( 'field_id' => 'Key', 'name' => 'FieldName', 'type' => 'DataType', 'options' => 'FieldOptions', ), 'custom_field_type' => array( // Us => Them 'input' => 'Text', 'select' => 'MultiSelectOne', 'checkbox' => 'MultiSelectMany', // Them => Us 'Text' => 'input', 'Number' => 'input', 'Date' => 'input', 'MultiSelectOne' => 'select', 'MultiSelectMany' => 'checkbox', ), ); return parent::get_data_keymap( $keymap ); } /** * @inheritDoc */ public function fetch_subscriber_lists() { if ( empty( $this->data['api_key'] ) ) { return $this->API_KEY_REQUIRED; } $clients = $this->_get_clients(); $lists = array(); if ( ! is_array( $clients ) ) { // Request failed with an error, return the error message. return $clients; } foreach ( $clients as $client_info ) { if ( empty( $client_info['ClientID'] ) ) { continue; } $url = "{$this->BASE_URL}/clients/{$client_info['ClientID']}/lists.json"; $this->prepare_request( $url ); parent::fetch_subscriber_lists(); if ( $this->response->ERROR ) { return $this->get_error_message(); } if ( isset( $this->response->DATA ) ) { $with_counts = $this->_get_subscriber_counts(); $lists = $lists + $with_counts; $this->data['is_authorized'] = true; $this->save_data(); } } if ( empty( $this->data['lists'] ) || ! empty( $lists ) ) { $this->data['lists'] = $lists; $this->save_data(); } return $this->is_authenticated() ? 'success' : $this->FAILURE_MESSAGE; } /** * @inheritDoc */ public function subscribe( $args, $url = '' ) { $url = "{$this->BASE_URL}/subscribers/{$args['list_id']}.json"; $params = $this->transform_data_to_provider_format( $args, 'subscriber' ); $params = $this->_process_custom_fields( $params ); $params['CustomFields'][] = array( 'Key' => 'Note', 'Value' => $this->SUBSCRIBED_VIA ); $this->prepare_request( $url, 'POST', false, $params, true ); return parent::subscribe( $params, $url ); } } social/Network.php000064400000001456152214676150010177 0ustar00service_type = 'social'; parent::__construct( $owner, $account_name ); } /** * @inheritDoc */ protected function _get_data_keys() { // Implement _get_data_keys() method. } /** * @inheritDoc */ public function get_account_fields() { // Implement get_fields() method. } /** * @inheritDoc */ protected function _get_accounts_data() { // Implement _get_accounts_data() method. } /** * @inheritDoc */ public function get_data_keymap( $keymap = array(), $custom_fields_key = '' ) { // Implement get_data_keymap() method. } /** * @inheritDoc */ public function save_data() { // Implement save_data() method. } }spam/init.php000064400000004536152214676150007201 0ustar00get( 'recaptcha', '' ); } } endif; if ( ! function_exists('et_builder_spam_add_account' ) ): function et_core_api_spam_add_account( $name_or_slug, $account, $api_key ) { et_core_security_check(); if ( empty( $name_or_slug ) || empty( $account ) ) { return __( 'ERROR: Invalid arguments.', 'et_core' ); } $providers = ET_Core_API_Spam_Providers::instance(); $provider = $providers->get( $name_or_slug, $account, 'builder' ); if ( ! $provider ) { return ''; } if ( is_array( $api_key ) ) { foreach ( $api_key as $field_name => $value ) { $provider->data[ $field_name ] = sanitize_text_field( $value ); } } else if ( '' !== $api_key ) { $provider->data['api_key'] = sanitize_text_field( $api_key ); } $provider->save_data(); return 'success'; } endif; if ( ! function_exists( 'et_core_api_spam_find_provider_account' ) ): function et_core_api_spam_find_provider_account() { $spam_providers = ET_Core_API_Spam_Providers::instance(); if ( $accounts = $spam_providers->accounts() ) { $enabled_account = ''; $provider = ''; foreach ( $accounts as $provider_slug => $provider_accounts ) { if ( empty( $provider_accounts ) ) { continue; } foreach ( $provider_accounts as $account_name => $account ) { if ( isset( $account['site_key'], $account['secret_key'] ) ) { $provider = $provider_slug; $enabled_account = $account_name; break; } } } if ( $provider && $enabled_account ) { return $spam_providers->get( $provider, $enabled_account ); } } return false; } endif; if ( ! function_exists( 'et_core_api_spam_remove_account' ) ): /** * Delete an existing provider account. * * @since 4.0.7 * * @param string $name_or_slug The provider name or slug. * @param string $account The account name. */ function et_core_api_spam_remove_account( $name_or_slug, $account ) { et_core_security_check(); if ( empty( $name_or_slug ) || empty( $account ) ) { return; } $providers = ET_Core_API_Spam_Providers::instance(); if ( $provider = $providers->get( $name_or_slug, $account ) ) { $provider->delete(); } } endif; spam/ReCaptcha.php000064400000010612152214676150010060 0ustar00_add_actions_and_filters(); } protected function _add_actions_and_filters() { if ( ! is_admin() && ! et_core_is_fb_enabled() ) { add_action( 'wp_enqueue_scripts', array( $this, 'action_wp_enqueue_scripts' ) ); } } public function action_wp_enqueue_scripts() { if ( ! $this->is_enabled() ) { return; } /** * reCAPTCHA v3 actions may only contain alphanumeric characters and slashes/underscore. * https://developers.google.com/recaptcha/docs/v3#actions * * Replace all non-alphanumeric characters with underscore. * Ex: '?page_id=254980' => '_page_id_254980' */ $action = preg_replace( '/[^A-Za-z0-9]/', '_', basename( get_the_permalink() ) ); $deps = array( 'jquery', 'es6-promise', 'et-recaptcha-v3' ); wp_register_script( 'et-recaptcha-v3', "https://www.google.com/recaptcha/api.js?render={$this->data['site_key']}", array(), ET_CORE_VERSION, true ); wp_register_script( 'es6-promise', ET_CORE_URL . 'admin/js/es6-promise.auto.min.js', array(), ET_CORE_VERSION, true ); wp_enqueue_script( 'et-core-api-spam-recaptcha', ET_CORE_URL . 'admin/js/recaptcha.js', $deps, ET_CORE_VERSION, true ); wp_localize_script( 'et-core-api-spam-recaptcha', 'et_core_api_spam_recaptcha', array( 'site_key' => empty( $this->data['site_key'] ) ? '' : $this->data['site_key'], 'page_action' => array( 'action' => $action ), ) ); } public function is_enabled() { $has_recaptcha_module = true; if ( class_exists( 'ET_Dynamic_Assets' ) ) { $et_dynamic_module_framework = et_builder_dynamic_module_framework(); $is_dynamic_framework_enabled = et_builder_is_frontend() && 'on' === $et_dynamic_module_framework; $is_dynamic_css_enabled = et_builder_is_frontend() && et_use_dynamic_css(); if ( $is_dynamic_framework_enabled && $is_dynamic_css_enabled ) { $et_dynamic_assets = ET_Dynamic_Assets::init(); $saved_shortcodes = $et_dynamic_assets->get_saved_page_shortcodes(); $recaptcha_modules = array( 'et_pb_contact_form', 'et_pb_signup' ); $has_recaptcha_module = ! empty( array_intersect( $saved_shortcodes, $recaptcha_modules ) ); } } $has_key = isset( $this->data['site_key'], $this->data['secret_key'] ) && et_()->all( array( $this->data['site_key'], $this->data['secret_key'] ) ); return $has_key && $has_recaptcha_module; } /** * Verify a form submission. * * @since 4.0.7 * * @global $_POST['token'] * * @return mixed[]|string $result { * Interaction Result * * @type bool $success Whether or not the request was valid for this site. * @type int $score Score for the request (0 < score < 1). * @type string $action Action name for this request (important to verify). * @type string $challenge_ts Timestamp of the challenge load (ISO format yyyy-MM-ddTHH:mm:ssZZ). * @type string $hostname Hostname of the site where the challenge was solved. * @type string[] $error-codes Optional * } */ public function verify_form_submission() { $args = array( 'secret' => $this->data['secret_key'], 'response' => et_()->array_get_sanitized( $_POST, 'token' ), 'remoteip' => et_core_get_ip_address(), ); $this->prepare_request( $this->BASE_URL, 'POST', false, $args ); $this->make_remote_request(); return $this->response->ERROR ? $this->response->ERROR_MESSAGE : $this->response->DATA; } /** * @inheritDoc */ public function get_account_fields() { return array( 'site_key' => array( 'label' => esc_html__( 'Site Key (v3)', 'et_core' ), ), 'secret_key' => array( 'label' => esc_html__( 'Secret Key (v3)', 'et_core' ), ), ); } /** * @inheritDoc */ public function get_data_keymap( $keymap = array() ) { return array( 'ip_address' => 'remoteip', 'response' => 'response', 'secret_key' => 'secret', ); } } spam/Provider.php000064400000007477152214676150010037 0ustar00account_name || ! is_string( $this->account_name ) ) { return array(); } $provider = sanitize_text_field( $this->slug ); $account = sanitize_text_field( $this->account_name ); if ( ! isset( $options['accounts'][ $provider ][ $account ] ) ) { $options['accounts'][ $provider ][ $account ] = array(); update_option( 'et_core_api_spam_options', $options ); } return $options['accounts'][ $provider ][ $account ]; } /** * Returns whether or not an account exists in the database. * * @since 4.0.7 * * @param string $provider * @param string $account_name * * @return bool */ public static function account_exists( $provider, $account_name ) { $all_accounts = self::get_accounts(); return isset( $all_accounts[ $provider ][ $account_name ] ); } /** * @since 4.0.7 * * @inheritDoc */ public function delete() { self::remove_account( $this->slug, $this->account_name ); $this->account_name = ''; $this->_get_data(); } /** * Retrieves the email accounts data from the database. * * @since 4.0.7 * * @return array */ public static function get_accounts() { $options = (array) get_option( 'et_core_api_spam_options' ); return isset( $options['accounts'] ) ? $options['accounts'] : array(); } /** * @since 4.0.7 * * @inheritDoc */ public function get_data_keymap( $keymap = array() ) { return $keymap; } abstract public function is_enabled(); /** * Remove an account * * @since 4.0.7 * * @param string $provider * @param string $account_name */ public static function remove_account( $provider, $account_name ) { $options = (array) get_option( 'et_core_api_spam_options' ); unset( $options['accounts'][ $provider ][ $account_name ] ); update_option( 'et_core_api_spam_options', $options ); } /** * @since 4.0.7 * * @inheritDoc */ public function save_data() { self::update_account( $this->slug, $this->account_name, $this->data ); } /** * @since 4.0.7 * * @inheritDoc */ public function set_account_name( $name ) { $this->account_name = $name; $this->data = $this->_get_data(); } /** * Remove keys with brackets. * * Fixing my errors is no walk in the park; it's more like a hike up Mt. * * @param array $data Options array. * @return void */ public static function remove_keys_with_brackets( &$data ) { foreach ( $data as $key => &$value ) { if ( is_array( $value ) ) { self::remove_keys_with_brackets( $value ); } if ( strpos( $key, '[' ) === 0 && strpos( $key, ']' ) === strlen( $key ) - 1 ) { unset( $data[ $key ] ); } } } /** * Updates the data for a provider account. * * @since 4.0.7 * * @param string $provider The provider's slug. * @param string $account The account name. * @param array $data The new data for the account. */ public static function update_account( $provider, $account, $data ) { if ( empty( $account ) || empty( $provider ) ) { return; } $options = (array) get_option( 'et_core_api_spam_options' ); $provider = sanitize_text_field( $provider ); $account = sanitize_text_field( $account ); self::remove_keys_with_brackets( $options ); self::$_->array_update( $options, "accounts.$provider.$account", $data ); update_option( 'et_core_api_spam_options', $options ); } abstract public function verify_form_submission(); } spam/Providers.php000064400000016205152214676150010207 0ustar00_initialize(); } } protected function _initialize() { self::$_ = ET_Core_Data_Utils::instance(); self::$_metadata = et_core_get_components_metadata(); $third_party_providers = et_core_get_third_party_components( 'api/spam' ); $load_fields = is_admin() || et_core_is_saving_builder_modules_cache() || et_core_is_fb_enabled() || isset( $_GET['et_fb'] ); // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification $all_names = array( 'official' => self::$_metadata['groups']['api/spam']['members'], 'third-party' => array_keys( $third_party_providers ), ); $_names_by_slug = array(); foreach ( $all_names as $provider_type => $provider_names ) { $_names_by_slug[ $provider_type ] = array(); foreach ( $provider_names as $provider_name ) { if ( 'Fields' === $provider_name || self::$_->includes( $provider_name, 'Provider' ) ) { continue; } if ( 'official' === $provider_type ) { $class_name = self::$_metadata[ $provider_name ]; $provider_slug = self::$_metadata[ $class_name ]['slug']; $provider = $load_fields ? new $class_name( 'ET_Core', '' ) : null; } else { $provider = $third_party_providers[ $provider_name ]; $provider_slug = is_object( $provider ) ? $provider->slug : ''; } if ( ! $provider_slug ) { continue; } $_names_by_slug[ $provider_type ][ $provider_slug ] = $provider_name; if ( $load_fields && is_object( $provider ) ) { self::$_fields[ $provider_slug ] = $provider->get_account_fields(); } } } /** * Filters the enabled anti-spam providers. * * @since 4.0.7 * * @param array[] $_names_by_slug { * * @type string[] $provider_type { * * @type string $slug Provider name * } * } */ self::$_names_by_slug = apply_filters( 'et_core_api_spam_enabled_providers', $_names_by_slug ); foreach ( array_keys( $all_names ) as $provider_type ) { self::$_names[ $provider_type ] = array_values( self::$_names_by_slug[ $provider_type ] ); self::$_slugs[ $provider_type ] = array_keys( self::$_names_by_slug[ $provider_type ] ); } } /** * Returns the spam provider accounts array from core. * * @since 4.0.7 * * @return array|mixed */ public function accounts() { return ET_Core_API_Spam_Provider::get_accounts(); } /** * @see {@link \ET_Core_API_Spam_Provider::account_exists()} */ public function account_exists( $provider, $account_name ) { return ET_Core_API_Spam_Provider::account_exists( $provider, $account_name ); } public function account_fields( $provider = 'all' ) { if ( 'all' !== $provider ) { if ( isset( self::$_fields[ $provider ] ) ) { return self::$_fields[ $provider ]; } if ( ! is_admin() && et_core_is_saving_builder_modules_cache() ) { // Need to initialize again because et_core_is_saving_builder_modules_cache // can't be called too early. $this->_initialize(); return et_()->array_get( self::$_fields, $provider, array() ); } return array(); } return self::$_fields; } /** * Get class instance for a provider. Instance will be created if necessary. * * @param string $name_or_slug The provider's name or slug. * @param string $account_name The identifier for the desired account with the provider. * @param string $owner The owner for the instance. * * @return ET_Core_API_Spam_Provider|bool The provider instance or `false` if not found. */ public function get( $name_or_slug, $account_name, $owner = 'ET_Core' ) { $name_or_slug = str_replace( ' ', '', $name_or_slug ); $is_official = isset( self::$_metadata[ $name_or_slug ] ); if ( ! $is_official && ! $this->is_third_party( $name_or_slug ) ) { return false; } if ( ! in_array( $name_or_slug, array_merge( self::names(), self::slugs() ) ) ) { return false; } // Make sure we have the component name if ( $is_official ) { $class_name = self::$_metadata[ $name_or_slug ]; $name = self::$_metadata[ $class_name ]['name']; } else { $components = et_core_get_third_party_components( 'api/spam' ); if ( ! $name = array_search( $name_or_slug, self::$_names_by_slug['third-party'] ) ) { $name = $name_or_slug; } } if ( ! isset( self::$providers[ $name ][ $owner ] ) ) { self::$providers[ $name ][ $owner ] = $is_official ? new $class_name( $owner, $account_name ) : $components[ $name ]; } return self::$providers[ $name ][ $owner ]; } public static function instance() { if ( null === self::$_instance ) { self::$_instance = new self; } return self::$_instance; } public function is_third_party( $name_or_slug ) { $is_third_party = in_array( $name_or_slug, self::$_names['third-party'] ); return $is_third_party ? $is_third_party : in_array( $name_or_slug, self::$_slugs['third-party'] ); } /** * Returns the names of available providers. List can optionally be filtered. * * @since 4.0.7 * * @param string $type The component type to include ('official'|'third-party'|'all'). Default is 'all'. * * @return array */ public static function names( $type = 'all' ) { if ( 'all' === $type ) { $names = array_merge( self::$_names['third-party'], self::$_names['official'] ); } else { $names = self::$_names[ $type ]; } return $names; } /** * Returns an array mapping the slugs of available providers to their names. * * @since 4.0.7 * * @param string $type The component type to include ('official'|'third-party'|'all'). Default is 'all'. * * @return array */ public function names_by_slug( $type = 'all' ) { if ( 'all' === $type ) { $names_by_slug = array_merge( self::$_names_by_slug['third-party'], self::$_names_by_slug['official'] ); } else { $names_by_slug = self::$_names_by_slug[ $type ]; } return $names_by_slug; } /** * @see {@link \ET_Core_API_Spam_Provider::remove_account()} */ public function remove_account( $provider, $account_name ) { ET_Core_API_Spam_Provider::remove_account( $provider, $account_name ); } /** * Returns the slugs of available providers. List can optionally be filtered. * * @since 4.0.7 * * @param string $type The component type to include ('official'|'third-party'|'all'). Default is 'all'. * * @return array */ public static function slugs( $type = 'all' ) { if ( 'all' === $type ) { $names = array_merge( self::$_slugs['third-party'], self::$_slugs['official'] ); } else { $names = self::$_slugs[ $type ]; } return $names; } /** * @since 4.0.7 * * @see {@link \ET_Core_API_Spam_Provider::update_account()} */ public function update_account( $provider, $account, $data ) { ET_Core_API_Spam_Provider::update_account( $provider, $account, $data ); } } init.php000064400000000302152214676150006224 0ustar00_initialize( $data, $urls ); $this->sha1_method = new ET_Core_LIB_OAuthHMACSHA1(); $this->consumer = new ET_Core_LIB_OAuthConsumer( $this->consumer_key, $this->consumer_secret ); if ( '' !== $this->access_token && '' !== $this->access_token_secret ) { $this->token = new ET_Core_LIB_OAuthToken( $this->access_token, $this->access_token_secret ); } else if ( empty( $this->access_token ) && ! empty( $this->access_token_secret ) ) { $this->bearer = "Bearer {$this->access_token_secret}"; } } /** * @internal * * @param array $data {@see self::__construct()} * @param array $urls {@see self::__construct()} */ private function _initialize( $data, $urls ) { $this->consumer_key = isset( $data['consumer_key'] ) ? $data['consumer_key'] : ''; $this->consumer_secret = isset( $data['consumer_secret'] ) ? $data['consumer_secret'] : ''; $this->access_token = isset( $data['access_key'] ) ? $data['access_key'] : ''; $this->access_token_secret = isset( $data['access_secret'] ) ? $data['access_secret'] : ''; $this->REQUEST_TOKEN_URL = $urls['request_token_url']; $this->AUTHORIZATION_URL = $urls['authorization_url']; $this->ACCESS_TOKEN_URL = $urls['access_token_url']; $this->REDIRECT_URL = isset( $urls['redirect_url'] ) ? $urls['redirect_url'] : ''; } protected function _get_oauth2_parameters( $args ) { et_core_nonce_verified_previously(); return wp_parse_args( $args, array( 'grant_type' => 'authorization_code', 'code' => sanitize_text_field( $_GET['code'] ), 'client_id' => $this->consumer_key, 'client_secret' => $this->consumer_secret, 'redirect_uri' => $this->REDIRECT_URL, ) ); } /** * @param \ET_Core_HTTPRequest $request * * @return \ET_Core_HTTPRequest */ protected function _prepare_oauth_request( $request ) { $parameters = array(); if ( is_array( $request->BODY ) && $request->BODY && ! $request->JSON_BODY ) { $parameters = $request->BODY; } $oauth_request = ET_Core_LIB_OAuthRequest::from_consumer_and_token( $this->consumer, $this->token, $request->METHOD, $request->URL, $parameters ); $oauth_request->sign_request( $this->sha1_method, $this->consumer, $this->token ); if ( 'GET' === $request->METHOD ) { $request->URL = $oauth_request->to_url(); } else if ( 'POST' === $request->METHOD ) { $request->URL = $request->JSON_BODY ? $oauth_request->to_url() : $oauth_request->get_normalized_http_url(); $request->BODY = $request->JSON_BODY ? json_encode( $request->BODY ) : $oauth_request->to_post_data(); } return $request; } /** * @param \ET_Core_HTTPRequest $request * * @return \ET_Core_HTTPRequest */ protected function _prepare_oauth2_request( $request ) { if ( null !== $this->bearer ) { $request->HEADERS['Authorization'] = $this->bearer; } if ( $request->JSON_BODY ) { return $request; } if ( is_array( $request->BODY ) && ! array_key_exists( 'code', $request->BODY ) ) { $request->URL = add_query_arg( $request->BODY, $request->URL ); $request->BODY = null; } return $request; } /** * Finish the OAuth2 authorization process if needed. */ public static function finish_oauth2_authorization() { et_core_nonce_verified_previously(); if ( ! isset( $_GET['state'] ) || 0 !== strpos( $_GET['state'], 'ET_Core' ) ) { return; } list( $_, $name, $account, $nonce ) = explode( '|', sanitize_text_field( rawurldecode( $_GET['state'] ) ) ); if ( ! $name || ! $account || ! $nonce ) { return; } $_GET['nonce'] = $nonce; et_core_security_check( 'manage_options', 'et_core_api_service_oauth2', 'nonce', '_GET' ); $providers = et_core_api_email_providers(); if ( ! $providers->account_exists( $name, $account ) ) { et_core_die(); } if ( ! $provider = $providers->get( $name, $account, 'ET_Core' ) ) { et_core_die(); } $result = $provider->fetch_subscriber_lists(); // Display the authorization results echo et_core_esc_previously( ET_Bloom::generate_modal_warning( $result ) ); } /** * Prepare a request for an access token. * * @param array $args { * For OAuth 1.0 & 1.0a: * * @type string $verifier OAuth verifier token. Optional. * * For OAuth 2.0: * * @type string $code The code returned when the user was redirected back to their dashboard. * @type string $grant_type The desired grant type, as per the OAuth 2.0 spec. * @type string $redirect_uri The redirect URL from the original authorization request. * } * * @return ET_Core_HTTPRequest */ public function prepare_access_token_request( $args = array() ) { et_core_nonce_verified_previously(); $oauth2 = ! empty( $_GET['code'] ); $request = new ET_Core_HTTPRequest( $this->ACCESS_TOKEN_URL, 'POST', '', true ); $request->BODY = $oauth2 ? $this->_get_oauth2_parameters( $args ) : $args; return $this->prepare_oauth_request( $request, $oauth2 ); } /** * Prepare an OAuth 1.0a or 2.0 request. * * @param ET_Core_HTTPRequest $request * @param bool $oauth2 * * @return \ET_Core_HTTPRequest */ function prepare_oauth_request( $request, $oauth2 = false ) { return $oauth2 ? $this->_prepare_oauth2_request( $request ) : $this->_prepare_oauth_request( $request ); } /** * Process a response to an OAuth access token request and retrieve the access token if auth was successful. * * @param \ET_Core_HTTPResponse $response */ public function process_authentication_response( $response, $json = true ) { if ( $response->ERROR ) { return; } $response = $json ? $response->DATA : wp_parse_args( $response->DATA ); // Salesforce returns an `instance_url` data in the auth response. if ( isset( $response['instance_url'] ) ) { $this->INSTANCE_URL = esc_url( $response['instance_url'] ); // @phpcs:ignore ET.Sniffs.ValidVariableName.UsedPropertyNotSnakeCase -- Use uppercase to be consistent with existing code. } if ( isset( $response['oauth_token'], $response['oauth_token_secret'] ) ) { // OAuth 1.0a $token = sanitize_text_field( $response['oauth_token'] ); $secret = sanitize_text_field( $response['oauth_token_secret'] ); $this->token = new ET_Core_LIB_OAuthToken( $token, $secret ); } elseif ( isset( $response['access_token'] ) ) { // OAuth 2.0 $this->token = new ET_Core_LIB_OAuthToken( '', sanitize_text_field( $response['access_token'] ) ); if ( isset( $response['refresh_token'] ) ) { $this->token->refresh_token = sanitize_text_field( $response['refresh_token'] ); } } } } Service.php000064400000035063152214676150006675 0ustar00request} * * @since 1.1.0 * @var \ET_Core_HTTPRequest? */ public $request; /** * Convenience accessor for {@link self::http->response} * * @since 1.1.0 * @var \ET_Core_HTTPResponse? */ public $response; /** * For services that return JSON responses, this is the top-level/root key for the returned data. * * @since 1.1.0 * @var string */ public $response_data_key; /** * The service type (email, social, etc). * * @since 1.1.0 * @var string */ public $service_type; /** * The slug for this service (not shown in the UI). * * @since 1.1.0 * @var string */ public $slug; /** * Whether or not the service uses OAuth. * * @since 1.1.0 * @var bool */ public $uses_oauth; /** * Data Utility class. * * @var ET_Core_Data_Utils */ public $data_utils; // phpcs:disable ET.Sniffs.ValidVariableName.PropertyNotSnakeCase -- Existing codebase. /** * Error message for when API Key is required. * * @var string */ public $API_KEY_REQUIRED; // phpcs:enable ET.Sniffs.ValidVariableName.PropertyNotSnakeCase -- Existing codebase. /** * ET_Core_API_Service constructor. * * @since 1.1.0 * * @param string $owner {@see self::owner} * @param string $account_name The name of the service account that the instance will provide access to. * @param string $api_key The api key for the account. Optional (can be set after instantiation). */ public function __construct( $owner = 'ET_Core', $account_name = '', $api_key = '' ) { $this->account_name = str_replace( '.', '', sanitize_text_field( $account_name ) ); $this->owner = sanitize_text_field( $owner ); $this->account_fields = $this->get_account_fields(); $this->data = $this->_get_data(); $this->data_keys = $this->get_data_keymap(); $this->oauth_verifier = ''; $this->http = new ET_Core_HTTPInterface( $this->owner ); self::$_ = $this->data_utils = new ET_Core_Data_Utils(); $this->FAILURE_MESSAGE = esc_html__( 'API request failed, please try again.', 'et_core' ); $this->API_KEY_REQUIRED = esc_html__( 'API request failed. API Key is required.', 'et_core' ); if ( '' !== $api_key ) { $this->data['api_key'] = sanitize_text_field( $api_key ); $this->save_data(); } if ( $this->uses_oauth && $this->is_authenticated() ) { $this->_initialize_oauth_helper(); } } /** * Generates a HTTP Basic Auth header and adds it to the current request object. Uses the value * of {@link self::http_auth} to determine the correct values to use for the username and password. */ protected function _add_http_auth_header_to_request() { $username_key = $this->http_auth['username']; $password_key = $this->http_auth['password']; $username = isset( $this->data[ $username_key ] ) ? $this->data[ $username_key ] : $username_key; $password = isset( $this->data[ $password_key ] ) ? $this->data[ $password_key ] : $password_key; $this->request->HEADERS['Authorization'] = 'Basic ' . base64_encode( "{$username}:{$password}" ); } /** * Exchange a request/verifier token for an access token. This is the last step in the OAuth authorization process. * If successful, the access token will be saved and used for future calls to the API. * * @return bool Whether or not authentication was successful. */ private function _do_oauth_access_token_request() { if ( ! $this->_initialize_oauth_helper() ) { return false; } $args = array(); if ( '' !== $this->oauth_verifier ) { $args['oauth_verifier'] = $this->oauth_verifier; } $this->request = $this->http->request = $this->OAuth_Helper->prepare_access_token_request( $args ); $this->request->HEADERS['Content-Type'] = 'application/x-www-form-urlencoded'; $this->http->make_remote_request(); $this->response = $this->http->response; if ( $this->response->ERROR ) { return false; } $this->OAuth_Helper->process_authentication_response( $this->response, $this->http->expects_json ); if ( null === $this->OAuth_Helper->token ) { return false; } $this->data['access_key'] = $this->OAuth_Helper->token->key; $this->data['access_secret'] = $this->OAuth_Helper->token->secret; $this->data['is_authorized'] = true; if ( ! empty( $this->OAuth_Helper->token->refresh_token ) ) { $this->data['refresh_token'] = $this->OAuth_Helper->token->refresh_token; } // If there an `instance_url` returned from the auth response, save it. // Salesforce API should use this URL instead of the `login_url` provided by user. if ( ! empty( $this->OAuth_Helper->INSTANCE_URL ) ) { // @phpcs:ignore ET.Sniffs.ValidVariableName.UsedPropertyNotSnakeCase -- No need to change the prop name. $this->data['instance_url'] = $this->OAuth_Helper->INSTANCE_URL; // @phpcs:ignore ET.Sniffs.ValidVariableName.UsedPropertyNotSnakeCase -- No need to change the prop name. } return true; } /** * The service's private data. * * @see self::$_data * @internal * @since 1.1.0 * * @return array */ protected function _get_data() { return (array) get_option( "et_core_api_{$this->service_type}_options" ); } /** * Initializes {@link self::OAuth_Helper} * * @return bool `true` if successful, `false` otherwise. */ protected function _initialize_oauth_helper() { if ( null !== $this->OAuth_Helper ) { return true; } $urls = array( 'access_token_url' => $this->ACCESS_TOKEN_URL, 'request_token_url' => $this->REQUEST_TOKEN_URL, 'authorization_url' => $this->AUTHORIZATION_URL, 'redirect_url' => $this->REDIRECT_URL, ); $this->OAuth_Helper = new ET_Core_API_OAuthHelper( $this->data, $urls, $this->owner ); return null !== $this->OAuth_Helper; } /** * Returns the currently known custom fields for this service. * * @return array */ protected function _get_custom_fields() { return empty( $this->data['custom_fields'] ) ? array() : $this->data['custom_fields']; } /** * Initiate OAuth Authorization Flow * * @return array|bool */ public function authenticate() { et_core_nonce_verified_previously(); if ( '1.0a' === $this->oauth_version || ( '2.0' === $this->oauth_version && ! empty( $_GET['code'] ) ) ) { $authenticated = $this->_do_oauth_access_token_request(); if ( $authenticated ) { $this->save_data(); return true; } } elseif ( '2.0' === $this->oauth_version ) { $nonce = wp_create_nonce( 'et_core_api_service_oauth2' ); $args = array( 'client_id' => $this->data['api_key'], 'response_type' => 'code', 'state' => rawurlencode( "ET_Core|{$this->slug}|{$this->account_name}|{$nonce}" ), 'redirect_uri' => $this->REDIRECT_URL, // @phpcs:ignore -- No need to change the class property ); $this->save_data(); return array( 'redirect_url' => add_query_arg( $args, $this->AUTHORIZATION_URL ) ); } return false; } /** * Remove the service account from the database. This cannot be undone. The instance * will no longer be usable after a call to this method. * * @since 1.1.0 */ abstract public function delete(); /** * Get the form fields to show in the WP Dashboard for this service's accounts. * * @since 1.1.0 * * @return array */ abstract public function get_account_fields(); /** * Get an array that maps our data keys to those returned by the 3rd-party service's API. * * @since 1.1.0 * * @param array $keymap A mapping of our data key addresses to those of the service, organized by type/category. * * @return array[] { * * @type array $key_type { * * @type string $our_key_address The corresponding key address on the service. * ... * } * ... * } */ abstract public function get_data_keymap( $keymap = array() ); /** * Get error message for a response that has an ERROR status. If possible the provider's * error message will be returned. Otherwise the HTTP error status description will be returned. * * @return string */ public function get_error_message() { if ( ! empty( $this->data_keys['error'] ) ) { $data = $this->transform_data_to_our_format( $this->response->DATA, 'error' ); return isset( $data['error_message'] ) ? $data['error_message'] : ''; } return $this->response->ERROR_MESSAGE; } /** * Whether or not the current account has been authenticated with the service's API. * * @return bool */ public function is_authenticated() { return isset( $this->data['is_authorized'] ) && in_array( $this->data['is_authorized'], array( true, 'true' ) ); } /** * Makes a remote request using the current {@link self::http->request}. Automatically * handles custom headers and OAuth when applicable. */ public function make_remote_request() { if ( ! empty( $this->custom_headers ) ) { $this->http->request->HEADERS = array_merge( $this->http->request->HEADERS, $this->custom_headers ); } if ( $this->uses_oauth ) { $oauth2 = '2.0' === $this->oauth_version; $this->http->request = $this->OAuth_Helper->prepare_oauth_request( $this->http->request, $oauth2 ); } else if ( $this->http_auth ) { $this->_add_http_auth_header_to_request(); } $this->request = $this->http->request; $this->http->make_remote_request(); $this->response = $this->http->response; } /** * Convenience accessor for {@link self::http->prepare_request()} * * @param string $url * @param string $method * @param bool $is_auth * @param mixed $body * @param bool $json_body * @param bool $ssl_verify */ public function prepare_request( $url, $method = 'GET', $is_auth = false, $body = null, $json_body = false, $ssl_verify = true ) { $this->http->prepare_request( $url, $method, $is_auth, $body, $json_body, $ssl_verify ); $this->request = $this->http->request; } /** * Save this service's data to the database. * * @return mixed */ abstract public function save_data(); /** * Set the account name for the instance. Changing the accounts name affects the * value of {@link self::data}. * * @param string $name */ abstract public function set_account_name( $name ); /** * Transforms an array from our data format to that of the service provider. * * @param array $data The data to be transformed. * @param string $key_type The type of data. This corresponds to the key_type in {@link self::data_keys}. * @param array $exclude_keys Keys that should be excluded from the transformed data. * * @return array */ public function transform_data_to_our_format( $data, $key_type, $exclude_keys = array() ) { if ( ! isset( $this->data_keys[ $key_type ] ) ) { return array(); } return self::$_->array_transform( $data, $this->data_keys[ $key_type ], '<-', $exclude_keys ); } /** * Transforms an array from the service provider's data format to our data format. * * @param array $data The data to be transformed. * @param string $key_type The type of data. This corresponds to the key_type in {@link self::data_keys}. * @param array $exclude_keys Keys that should be excluded from the transformed data. * * @return array */ public function transform_data_to_provider_format( $data, $key_type, $exclude_keys = array() ) { if ( ! isset( $this->data_keys[ $key_type ] ) ) { return array(); } return self::$_->array_transform( $data, $this->data_keys[ $key_type ], '->', $exclude_keys ); } } README.md000064400000001201152214676150006026 0ustar00## Core API Component Group This directory contains components that facilitate interacting with 3rd-party REST APIs. ### What's Inside |File|Name|Description| |:--------|:----------|:----------| |**email**|**ET_Core_API_Email**|Email marketing service providers| |**social**|**ET_Core_API_Social**|Social networks| |Service.php|ET_Core_API_Service|Base class for all API components| |OAuthHelper.php|ET_Core_API_OAuthHelper|Handles OAuth authorization flow| > ***Note:*** Component groups are in **bold**. ### Class Hierarchy

ElegantThemes.php000064400000013147152214676150010021 0ustar00username = sanitize_text_field( $username ); $this->api_key = sanitize_text_field( $api_key ); } /** * Decorate a payload array with common data. * * @since 3.10 * * @param array $payload * * @return array */ protected function _get_decorated_payload( $payload ) { if ( ! isset( $payload['username'] ) ) { $payload['username'] = $this->username; } if ( ! isset( $payload['api_key'] ) ) { $payload['api_key'] = $this->api_key; } return $payload; } /** * Decorate request options array with common options. * * @since 3.10 * * @param array $options * * @return array */ protected function _get_decorated_request_options( $options = array() ) { global $wp_version; $options = array_merge( array( 'timeout' => 10, 'user-agent' => 'WordPress/' . $wp_version . '; Elegant Themes/' . ET_CORE_VERSION . '; ' . home_url( '/' ), ), $options ); return $options; } /** * Parse a response from the API. * * @since 3.10 * * @param array|WP_Error $response * * @return object|WP_Error */ protected function _parse_response( $response ) { if ( is_wp_error( $response ) ) { return $response; } $response_body = trim( wp_remote_retrieve_body( $response ) ); if ( '' === $response_body ) { return new WP_Error( 'et_unknown', esc_html__( 'An unknown error has occurred. Please try again later.', 'et-core' ) ); } $credentials_errors = array( 'Username is not set.', 'Subscription is not active', ); if ( in_array( $response_body, $credentials_errors ) ) { return new WP_Error( 'et_invalid_api_credentials', esc_html__( 'Invalid Username and/or API Key provided.', 'et-core' ) ); } return maybe_unserialize( $response_body ); } /** * Get the full API endpoint. * * @since 3.10 * * @param string $endpoint "api" or "api_downloads" * * @return string */ protected function _get_endpoint( $endpoint = 'api' ) { $allowed_endpoints = array( 'api', 'api_downloads' ); $suffix = '.php'; if ( ! in_array( $endpoint, $allowed_endpoints ) ) { $endpoint = $allowed_endpoints[0]; } return esc_url_raw( $this->api_url . $endpoint . $suffix ); } /** * Submit a GET request to the API. * * @since 3.10 * * @param array $payload * @param string $endpoint * * @return object|WP_Error */ protected function _get( $payload, $endpoint = 'api' ) { $payload = $this->_get_decorated_payload( $payload ); $options = $this->_get_decorated_request_options(); $url = esc_url_raw( add_query_arg( $payload, $this->_get_endpoint( $endpoint ) ) ); $response = wp_remote_get( $url, $options ); return $this->_parse_response( $response ); } /** * Submit a POST request to the API. * * @since 3.10 * * @param array $payload * @param string $endpoint * * @return object|WP_Error */ protected function _post( $payload, $endpoint = 'api' ) { $payload = $this->_get_decorated_payload( $payload ); $options = $this->_get_decorated_request_options( array( 'body' => $payload, ) ); $response = wp_remote_post( $this->_get_endpoint( $endpoint ), $options ); return $this->_parse_response( $response ); } /** * Check if a product is available. * * @since 3.10 * * @param string $product_name * @param string $version * * @return bool|WP_Error */ public function is_product_available( $product_name, $version ) { $response = $this->_get( array( 'api_update' => 1, 'action' => 'check_version_status', 'product' => $product_name, 'version' => $version, ) ); if ( is_wp_error( $response ) ) { return $response; } if ( ! is_array( $response ) ) { return new WP_Error( 'et_unknown', esc_html__( 'An unexpected response was received from the version server. Please try again later.', 'et-core' ) ); } switch ( $response['status'] ) { case 'not_available': return new WP_Error( 'et_version_rollback_not_available', sprintf( esc_html__( 'The previously used version of %1$s does not support version rollback.', 'et-core' ), esc_html( $product_name ) ) ); case 'blocklisted': return new WP_Error( 'et_version_rollback_blocklisted', et_get_safe_localization( sprintf( __( 'For privacy and security reasons, you cannot rollback to Version %1$s.', 'et-core' ), esc_html( $version ) ) ) ); case 'available': return true; } return new WP_Error( 'et_unknown', esc_html__( 'An unknown error has occurred. Please try again later.', 'et-core' ) ); } /** * Get a product download url for a specific version, if available. * * @since 3.10 * * @param string $product_name * @param string $version * * @return string|WP_Error */ public function get_download_url( $product_name, $version ) { $payload = $this->_get_decorated_payload( array( 'api_update' => 1, 'theme' => $product_name, 'version' => $version, ) ); return esc_url_raw( add_query_arg( $payload, $this->_get_endpoint( 'api_downloads' ) ) ); } } endif; rest/BlockLayout.php000064400000017140152215004310010456 0ustar00register(); } /** * Get class instance * * @since 4.1.0 * * @return object class instance */ public static function instance() { if ( null === self::$_instance ) { self::$_instance = new self(); } return self::$_instance; } /** * Register callback for Layout block REST API * * @since 4.1.0 */ public function register() { add_action( 'rest_api_init', array( $this, 'register_routes' ) ); } /** * Register REST API routes for Layout block * * @since 4.1.0 */ public function register_routes() { register_rest_route( 'divi/v1', 'get_layout_content', array( 'methods' => 'POST', 'callback' => array( $this, 'get_layout_content_callback' ), 'args' => array( 'id' => array( // using intval directly doesn't work, hence the custom callback. 'sanitize_callback' => array( $this, 'sanitize_int' ), 'validation_callback' => 'is_numeric', ), 'nonce' => array( 'sanitize_callback' => 'sanitize_text_field', ), ), 'permission_callback' => array( $this, 'rest_api_layout_block_permission' ), ) ); register_rest_route( 'divi/v1', 'block/layout/builder_edit_data', array( 'methods' => 'POST', 'callback' => array( $this, 'process_builder_edit_data' ), 'args' => array( 'action' => array( 'sanitize_callback' => array( $this, 'sanitize_action' ), // update|delete|get. 'validation_callback' => array( $this, 'validate_action' ), ), 'postId' => array( 'sanitize_callback' => array( $this, 'sanitize_int' ), 'validation_callback' => 'is_numeric', ), 'blockId' => array( 'sanitize_callback' => 'sanitize_title', ), 'layoutContent' => array( 'sanitize_callback' => 'wp_kses_post', ), 'nonce' => array( 'sanitize_callback' => 'sanitize_text_field', ), ), 'permission_callback' => array( $this, 'rest_api_layout_block_permission' ), ) ); } /** * Get layout content based on given post ID * * @since 4.1.0 * * @param WP_REST_Request $request Full details about the request. * * @return string|WP_Error */ public function get_layout_content_callback( WP_REST_Request $request ) { $post_id = $request->get_param( 'id' ); $nonce = $request->get_param( 'nonce' ); // Action nonce check. REST API actually has checked for nonce at cookie sent on every // request and performed capability-based check. This check perform action-based nonce // check to strengthen the security // @see https://developer.wordpress.org/rest-api/using-the-rest-api/authentication/. if ( ! wp_verify_nonce( $nonce, 'et_rest_get_layout_content' ) ) { return new WP_Error( 'invalid_nonce', esc_html__( 'Invalid nonce', 'et_builder' ), array( 'status' => 400, ) ); } // request has to have id param. if ( ! $post_id ) { return new WP_Error( 'no_layout_id', esc_html__( 'No layout id found', 'et_builder' ), array( 'status' => 400, ) ); } $post = get_post( $post_id ); if ( ! isset( $post->post_content ) || ! $post->post_content ) { return new WP_Error( 'no_layout_found', esc_html__( 'No valid layout content found.', 'et_builder' ), array( 'status' => 404, ) ); } return $post->post_content; } /** * Process /block/layout/builder_edit_data route request * * @param WP_Rest_Request $request Request to prepare items for. * * @return string|WP_Error * @since 4.1.0 */ public function process_builder_edit_data( WP_Rest_Request $request ) { $post_id = $request->get_param( 'postId' ); $block_id = $request->get_param( 'blockId' ); $nonce = $request->get_param( 'nonce' ); // No post ID. if ( empty( $post_id ) ) { return new WP_Error( 'no_post_id', esc_html__( 'No post id', 'et_builder' ), array( 'status' => 400, ) ); } // No block ID. if ( empty( $block_id ) ) { return new WP_Error( 'no_block_id', esc_html__( 'No block id', 'et_builder' ), array( 'status' => 400, ) ); } // Action nonce check. REST API actually has checked for nonce at cookie sent on every // request and performed capability-based check. This check perform action-based nonce // check to strengthen the security // @see https://developer.wordpress.org/rest-api/using-the-rest-api/authentication/. if ( ! wp_verify_nonce( $nonce, 'et_rest_process_builder_edit_data' ) ) { return new WP_Error( 'invalid_nonce', esc_html__( 'Invalid nonce', 'et_builder' ), array( 'status' => 400, ) ); } $result = ''; $post_meta_key = "_et_block_layout_preview_{$block_id}"; switch ( $request->get_param( 'action' ) ) { case 'get': $result = get_post_meta( $post_id, $post_meta_key, true ); break; case 'update': $layout_content = $request->get_param( 'layoutContent' ); // No layout content. if ( empty( $layout_content ) ) { return new WP_Error( 'no_layout_content', esc_html__( 'No layout content', 'et_builder' ), array( 'status' => 400, ) ); } $saved_layout_content = get_post_meta( $post_id, $post_meta_key, true ); if ( ! empty( $saved_layout_content ) && $saved_layout_content === $layout_content ) { // If for some reason layout exist and identical to the one being sent, return // true because update_post_meta() returns false if it updates the meta key and // the value doesn't change. $result = true; } else { // Otherwise, attempt to save post meta and returns how it goes. $result = update_post_meta( $post_id, $post_meta_key, $layout_content ); } break; case 'delete': $result = delete_post_meta( $post_id, $post_meta_key ); break; default: return new WP_Error( 'no_valid_action', esc_html__( 'No valid action found', 'et_builder' ), array( 'status' => 400, ) ); } return array( 'result' => $result, ); } /** * Sanitize int value * * @since 4.1.0 * * @param int|mixed $value Value. * * @return int */ public function sanitize_int( $value ) { return intval( $value ); } /** * Sanitize request "action" argument * * @since 4.1.0 * * @param string $value Action value. * * @return string */ public function sanitize_action( $value ) { return $this->validate_action( $value ) ? $value : ''; } /** * Validate request "action" argument * * @since 4.1.0 * * @param string $value Action value. * * @return bool */ public function validate_action( $value ) { $valid_builder_edit_data_actions = array( 'get', 'update', 'delete', ); return in_array( $value, $valid_builder_edit_data_actions, true ); } /** * Permission callback for get layout permalink REST API endpoint * * @since 4.1.0 * * @return bool */ public function rest_api_layout_block_permission() { return current_user_can( 'edit_posts' ) && et_pb_is_allowed( 'use_visual_builder' ); } } // Initialize ET_Api_Rest_Block_Layout. ET_Api_Rest_Block_Layout::instance(); DiviExtensions.php000064400000004633152215004310010227 0ustar00name ] ) ) { self::$_extensions[ $instance->name ] = $instance; } else { et_error( "A Divi Extension named {$instance->name} already exists!" ); } } /** * Get one or all Divi Extension instances. * * @since 3.1 * * @param string $name The extension name. Default: 'all'. * * @return DiviExtension|DiviExtension[]|null */ public static function get( $name = 'all' ) { if ( 'all' === $name ) { return self::$_extensions; } return self::$_->array_get( self::$_extensions, $name, null ); } /** * Initialize the base `DiviExtension` class. */ public static function initialize() { self::$_ = ET_Core_Data_Utils::instance(); require_once ET_BUILDER_DIR . 'api/DiviExtension.php'; /** * Fires when the {@see DiviExtension} base class is available. * * @since 3.1 */ do_action( 'divi_extensions_init' ); } /** * Whether or not a Divi Extension is in debug mode. * * @since 3.1 * * @return bool */ public static function is_debugging_extension() { return ! is_null( self::$_debugging_extension ); } /** * Register's an extension instance for debug mode if one hasn't already been registered. * * @since 3.1 * * @param DiviExtension $instance Instance. * * @return bool Whether or not request was successful */ public static function register_debug_mode( $instance ) { if ( ! self::$_debugging_extension ) { self::$_debugging_extension = $instance; return true; } return false; } } DiviExtensions::initialize(); DiviExtension.php000064400000021131152215004310010034 0ustar00name = $name; if ( $this->name ) { $this->_initialize(); } } /** * Enqueues minified, production javascript bundles. * * @since 3.1 */ protected function _enqueue_bundles() { // Frontend Bundle. $bundle_url = "{$this->plugin_dir_url}scripts/frontend-bundle.min.js"; wp_enqueue_script( "{$this->name}-frontend-bundle", $bundle_url, $this->_bundle_dependencies['frontend'], $this->version, true ); if ( et_core_is_fb_enabled() ) { // Builder Bundle. $bundle_url = "{$this->plugin_dir_url}scripts/builder-bundle.min.js"; wp_enqueue_script( "{$this->name}-builder-bundle", $bundle_url, $this->_bundle_dependencies['builder'], $this->version, true ); } } /** * Enqueues non-minified, hot reloaded javascript bundles. * * @since 3.1 */ protected function _enqueue_debug_bundles() { // Frontend Bundle. $site_url = wp_parse_url( get_site_url() ); $hot_bundle_url = "{$site_url['scheme']}://{$site_url['host']}:3000/static/js/frontend-bundle.js"; wp_enqueue_script( "{$this->name}-frontend-bundle", $hot_bundle_url, $this->_bundle_dependencies['frontend'], $this->version, true ); if ( et_core_is_fb_enabled() ) { // Builder Bundle. $hot_bundle_url = "{$site_url['scheme']}://{$site_url['host']}:3000/static/js/builder-bundle.js"; wp_enqueue_script( "{$this->name}-builder-bundle", $hot_bundle_url, $this->_bundle_dependencies['builder'], $this->version, true ); } } /** * Enqueues minified (production) or non-minified (hot reloaded) backend styles. * * @since 4.4.9 */ protected function _enqueue_backend_styles() { if ( $this->_debug ) { $site_url = wp_parse_url( get_site_url() ); $backend_styles_url = "{$site_url['scheme']}://{$site_url['host']}:3000/styles/backend-style.css"; } else { $extension_dir_path = plugin_dir_path( $this->plugin_dir ); $backend_styles_path = "{$extension_dir_path}styles/backend-style.min.css"; $backend_styles_url = "{$this->plugin_dir_url}styles/backend-style.min.css"; // Ensure backend style CSS file exists on production. if ( ! file_exists( $backend_styles_path ) ) { return; } } // Backend Styles - VB. wp_enqueue_style( "{$this->name}-backend-styles", $backend_styles_url, array(), $this->version ); } /** * Sets initial value of {@see self::$_bundle_dependencies}. * * @since 3.1 */ protected function _set_bundle_dependencies() { /** * Builder script handle name * * @since 3.?? * * @param string */ $this->_bundle_dependencies = array( 'builder' => array( 'react-dom', "{$this->name}-frontend-bundle" ), 'frontend' => array( 'jquery', et_get_combined_script_handle() ), ); } /** * Sets {@see self::$_debug} based on the extension's global DEBUG constant. * * @since 3.1 */ protected function _set_debug_mode() { $name_parts = explode( '_', get_class( $this ) ); $prefix = strtoupper( $name_parts[0] ); $debug = $prefix . '_DEBUG'; $this->_debug = defined( $debug ) && constant( $debug ); if ( $this->_debug && ! DiviExtensions::register_debug_mode( $this ) ) { $this->_debug = false; et_error( "You're Doing It Wrong! Only one Divi Extension can be in debug mode at a time." ); } } /** * Loads custom modules when the builder is ready. * * @since 3.1 * @deprecated ?? - Use {@see 'hook_et_builder_ready'} instead. */ public function hook_et_builder_modules_loaded() { $this->hook_et_builder_ready(); } /** * Loads custom modules when the builder is ready. * {@see 'et_builder_ready'} * * @since 4.10.0 */ public function hook_et_builder_ready() { if ( file_exists( trailingslashit( $this->plugin_dir ) . 'loader.php' ) ) { require_once trailingslashit( $this->plugin_dir ) . 'loader.php'; } } /** * Performs initialization tasks. * * @since 3.1 */ protected function _initialize() { DiviExtensions::add( $this ); $this->_set_debug_mode(); $this->_set_bundle_dependencies(); // Setup translations. if ( ! empty( $this->gettext_domain ) ) { load_plugin_textdomain( $this->gettext_domain, false, basename( $this->plugin_dir ) . '/languages' ); } // Register callbacks. register_activation_hook( trailingslashit( $this->plugin_dir ) . $this->name . '.php', array( $this, 'wp_hook_activate' ) ); register_deactivation_hook( trailingslashit( $this->plugin_dir ) . $this->name . '.php', array( $this, 'wp_hook_deactivate' ) ); add_action( 'et_builder_ready', array( $this, 'hook_et_builder_ready' ), 9 ); add_action( 'wp_enqueue_scripts', array( $this, 'wp_hook_enqueue_scripts' ) ); add_action( 'admin_enqueue_scripts', array( $this, 'admin_hook_enqueue_scripts' ) ); } /** * Performs tasks when the plugin is activated. * {@see 'activate_$PLUGINNAME'} * * @since 3.1 */ public function wp_hook_activate() { // Force the legacy backend builder to reload its template cache. // This ensures that custom modules are available for use right away. et_pb_force_regenerate_templates(); } /** * Performs tasks when the plugin is deactivated. * {@see 'deactivate_$PLUGINNAME'} * * @since 3.1 */ public function wp_hook_deactivate() {} /** * Enqueues the extension's scripts and styles. * {@see 'wp_enqueue_scripts'} * * @since 3.1 * @since 4.4.9 Added backend styles for handling custom builder styles. */ public function wp_hook_enqueue_scripts() { if ( $this->_debug ) { $this->_enqueue_debug_bundles(); } else { $styles = et_is_builder_plugin_active() ? 'style-dbp' : 'style'; $styles_url = "{$this->plugin_dir_url}styles/{$styles}.min.css"; wp_enqueue_style( "{$this->name}-styles", $styles_url, array(), $this->version ); $this->_enqueue_bundles(); } if ( et_core_is_fb_enabled() && ! et_builder_bfb_enabled() ) { $this->_enqueue_backend_styles(); } // Normalize the extension name to get actual script name. For example from 'divi-custom-modules' to `DiviCustomModules`. $extension_name = str_replace( ' ', '', ucwords( str_replace( '-', ' ', $this->name ) ) ); // Enqueue frontend bundle's data. if ( ! empty( $this->_frontend_js_data ) ) { wp_localize_script( "{$this->name}-frontend-bundle", "{$extension_name}FrontendData", $this->_frontend_js_data ); } // Enqueue builder bundle's data. if ( et_core_is_fb_enabled() && ! empty( $this->_builder_js_data ) ) { wp_localize_script( "{$this->name}-builder-bundle", "{$extension_name}BuilderData", $this->_builder_js_data ); } } /** * Enqueues the extension's scripts and styles for admin area. * * @since 4.4.9 */ public function admin_hook_enqueue_scripts() { if ( et_builder_bfb_enabled() || et_builder_is_tb_admin_screen() ) { $this->_enqueue_backend_styles(); } } } new DiviExtension(); error_log000064400000026731152215004310006463 0ustar00[16-Oct-2025 18:01:20 UTC] PHP Fatal error: Uncaught Error: Class "ET_Core_Data_Utils" not found in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtension.php:121 Stack trace: #0 /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtension.php(349): DiviExtension->__construct() #1 {main} thrown in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtension.php on line 121 [16-Oct-2025 18:02:02 UTC] PHP Fatal error: Uncaught Error: Class "ET_Core_Data_Utils" not found in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtensions.php:80 Stack trace: #0 /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtensions.php(123): DiviExtensions::initialize() #1 {main} thrown in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtensions.php on line 80 [17-Oct-2025 17:27:19 UTC] PHP Fatal error: Uncaught Error: Class "ET_Core_Data_Utils" not found in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtension.php:121 Stack trace: #0 /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtension.php(349): DiviExtension->__construct() #1 {main} thrown in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtension.php on line 121 [17-Oct-2025 17:44:16 UTC] PHP Fatal error: Uncaught Error: Class "ET_Core_Data_Utils" not found in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtensions.php:80 Stack trace: #0 /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtensions.php(123): DiviExtensions::initialize() #1 {main} thrown in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtensions.php on line 80 [17-Oct-2025 17:47:48 UTC] PHP Fatal error: Uncaught Error: Class "ET_Core_Data_Utils" not found in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtension.php:121 Stack trace: #0 /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtension.php(349): DiviExtension->__construct() #1 {main} thrown in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtension.php on line 121 [17-Oct-2025 17:57:23 UTC] PHP Fatal error: Uncaught Error: Class "ET_Core_Data_Utils" not found in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtensions.php:80 Stack trace: #0 /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtensions.php(123): DiviExtensions::initialize() #1 {main} thrown in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtensions.php on line 80 [14-Nov-2025 07:02:31 UTC] PHP Fatal error: Uncaught Error: Class "ET_Core_Data_Utils" not found in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtension.php:121 Stack trace: #0 /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtension.php(349): DiviExtension->__construct() #1 {main} thrown in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtension.php on line 121 [14-Nov-2025 07:02:43 UTC] PHP Fatal error: Uncaught Error: Class "ET_Core_Data_Utils" not found in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtensions.php:80 Stack trace: #0 /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtensions.php(123): DiviExtensions::initialize() #1 {main} thrown in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtensions.php on line 80 [15-Nov-2025 00:14:20 UTC] PHP Fatal error: Uncaught Error: Class "ET_Core_Data_Utils" not found in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtensions.php:80 Stack trace: #0 /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtensions.php(123): DiviExtensions::initialize() #1 {main} thrown in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtensions.php on line 80 [15-Nov-2025 00:17:11 UTC] PHP Fatal error: Uncaught Error: Class "ET_Core_Data_Utils" not found in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtension.php:121 Stack trace: #0 /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtension.php(349): DiviExtension->__construct() #1 {main} thrown in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtension.php on line 121 [15-Nov-2025 00:29:22 UTC] PHP Fatal error: Uncaught Error: Class "ET_Core_Data_Utils" not found in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtension.php:121 Stack trace: #0 /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtension.php(349): DiviExtension->__construct() #1 {main} thrown in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtension.php on line 121 [15-Nov-2025 00:33:34 UTC] PHP Fatal error: Uncaught Error: Class "ET_Core_Data_Utils" not found in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtensions.php:80 Stack trace: #0 /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtensions.php(123): DiviExtensions::initialize() #1 {main} thrown in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtensions.php on line 80 [15-Nov-2025 00:45:34 UTC] PHP Fatal error: Uncaught Error: Class "ET_Core_Data_Utils" not found in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtension.php:121 Stack trace: #0 /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtension.php(349): DiviExtension->__construct() #1 {main} thrown in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtension.php on line 121 [15-Nov-2025 00:46:03 UTC] PHP Fatal error: Uncaught Error: Class "ET_Core_Data_Utils" not found in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtensions.php:80 Stack trace: #0 /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtensions.php(123): DiviExtensions::initialize() #1 {main} thrown in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtensions.php on line 80 [15-Nov-2025 01:06:00 UTC] PHP Fatal error: Uncaught Error: Class "ET_Core_Data_Utils" not found in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtension.php:121 Stack trace: #0 /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtension.php(349): DiviExtension->__construct() #1 {main} thrown in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtension.php on line 121 [15-Nov-2025 01:09:03 UTC] PHP Fatal error: Uncaught Error: Class "ET_Core_Data_Utils" not found in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtensions.php:80 Stack trace: #0 /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtensions.php(123): DiviExtensions::initialize() #1 {main} thrown in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtensions.php on line 80 [17-Dec-2025 22:51:00 UTC] PHP Fatal error: Uncaught Error: Class "ET_Core_Data_Utils" not found in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtension.php:121 Stack trace: #0 /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtension.php(349): DiviExtension->__construct() #1 {main} thrown in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtension.php on line 121 [17-Dec-2025 22:51:02 UTC] PHP Fatal error: Uncaught Error: Class "ET_Core_Data_Utils" not found in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtensions.php:80 Stack trace: #0 /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtensions.php(123): DiviExtensions::initialize() #1 {main} thrown in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtensions.php on line 80 [02-Mar-2026 10:05:34 UTC] PHP Fatal error: Uncaught Error: Class "ET_Core_Data_Utils" not found in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtension.php:121 Stack trace: #0 /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtension.php(349): DiviExtension->__construct() #1 {main} thrown in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtension.php on line 121 [02-Mar-2026 10:10:04 UTC] PHP Fatal error: Uncaught Error: Class "ET_Core_Data_Utils" not found in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtensions.php:80 Stack trace: #0 /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtensions.php(123): DiviExtensions::initialize() #1 {main} thrown in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtensions.php on line 80 [06-Mar-2026 04:39:55 UTC] PHP Fatal error: Uncaught Error: Class "ET_Core_Data_Utils" not found in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtension.php:121 Stack trace: #0 /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtension.php(349): DiviExtension->__construct() #1 {main} thrown in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtension.php on line 121 [06-Mar-2026 04:39:56 UTC] PHP Fatal error: Uncaught Error: Class "ET_Core_Data_Utils" not found in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtension.php:121 Stack trace: #0 /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtension.php(349): DiviExtension->__construct() #1 {main} thrown in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtension.php on line 121 [17-Apr-2026 23:50:47 UTC] PHP Fatal error: Uncaught Error: Class "ET_Core_Data_Utils" not found in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtension.php:121 Stack trace: #0 /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtension.php(349): DiviExtension->__construct() #1 {main} thrown in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtension.php on line 121 [17-Apr-2026 23:51:00 UTC] PHP Fatal error: Uncaught Error: Class "ET_Core_Data_Utils" not found in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtensions.php:80 Stack trace: #0 /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtensions.php(123): DiviExtensions::initialize() #1 {main} thrown in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtensions.php on line 80 [25-Jun-2026 11:45:03 UTC] PHP Fatal error: Uncaught Error: Class "ET_Core_Data_Utils" not found in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtension.php:121 Stack trace: #0 /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtension.php(349): DiviExtension->__construct() #1 {main} thrown in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtension.php on line 121 [25-Jun-2026 11:45:04 UTC] PHP Fatal error: Uncaught Error: Class "ET_Core_Data_Utils" not found in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtension.php:121 Stack trace: #0 /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtension.php(349): DiviExtension->__construct() #1 {main} thrown in /home/toreyh/public_html/wp-content/themes/Divi/includes/builder/api/DiviExtension.php on line 121