m_Settings_Abstract ) {
if ( empty( $class_name ) ) {
return null;
}
if ( ! class_exists( $class_name ) ) {
return null;
}
try {
$form_settings_instance = new $class_name( $this, $module_id );
if ( ! $form_settings_instance instanceof Hustle_Provider_Form_Settings_Abstract ) {
throw new Exception( $class_name . ' is not instanceof Hustle_Provider_Form_Settings_Abstract' );
}
$this->provider_form_settings_instance[ $module_id ] = $form_settings_instance;
} catch ( Exception $e ) {
Hustle_Provider_Utils::maybe_log( $this->get_slug(), 'Failed to instantiate its _form_settings_instance', $e->getMessage() );
return null;
}
}
return $this->provider_form_settings_instance[ $module_id ];
}
/**
* Executor of before_get_form_settings values, to be correctly mapped with form_setting instance for module_id.
*
* @since 4.0.0
*
* @param array $values Settings to be stored.
* @param string $module_id ID of the module to store the settings into.
*
* @return mixed
*/
final public function before_get_form_settings_values( $values, $module_id ) {
$form_settings = $this->get_provider_form_settings( $module_id );
if ( $form_settings instanceof Hustle_Provider_Form_Settings_Abstract ) {
if ( is_callable( array( $form_settings, 'before_get_form_settings_values' ) ) ) {
return $form_settings->before_get_form_settings_values( $values );
}
}
return $values;
}
/**
* Executor of before_save_form_settings_ values, to be correctly mapped with form_setting instance for module_id
*
* @since 4.0.0
*
* @param array $values Settings to be stored.
* @param string $module_id ID of the module to store the settings into.
*
* @return mixed
*/
final public function before_save_form_settings_values( $values, $module_id ) {
$form_settings = $this->get_provider_form_settings( $module_id );
if ( $form_settings instanceof Hustle_Provider_Form_Settings_Abstract ) {
if ( is_callable( array( $form_settings, 'before_save_form_settings_values' ) ) ) {
return $form_settings->before_save_form_settings_values( $values );
}
}
return $values;
}
/**
* Get Form Hooks of Addons
*
* @since 4.0.0
*
* @param string $module_id Module ID.
* @return Hustle_Provider_Form_Hooks_Abstract|null
*/
final public function get_addon_form_hooks( $module_id ) {
if ( ! isset( $this->provider_form_hooks_instances[ $module_id ] ) || ! $this->provider_form_hooks_instances[ $module_id ] instanceof Hustle_Provider_Form_Hooks_Abstract ) {
if ( empty( $this->form_hooks ) ) {
return null;
}
if ( ! class_exists( $this->form_hooks ) ) {
return null;
}
try {
$classname = $this->form_hooks;
$this->provider_form_hooks_instances[ $module_id ] = new $classname( $this, $module_id );
} catch ( Exception $e ) {
Hustle_Provider_Utils::maybe_log( $this->get_slug(), 'Failed to instantiate its _addon_form_hooks_instance', $e->getMessage() );
return null;
}
}
return $this->provider_form_hooks_instances[ $module_id ];
}
/**
* Gets the requested wizard.
*
* @since 3.0.5
* @since 4.0.0 $module_id param added. $is_close, $is_submit, $data_to_save params removed.
*
* @param array $steps Array with all the wizard's steps from the integration.
* @param array $submitted_data Array with the submitted data. Softly sanitized by @see Opt_In_Utils::validate_and_sanitize_fields().
* @param string $module_id Module ID.
* @param int $step Step from which the call is made.
*
* @return array|mixed
*/
private function get_wizard( $steps, $submitted_data, $module_id, $step = 0 ) {
$total_steps = count( $steps );
$is_submit = ! empty( $submitted_data['hustle_is_submit'] );
// Validate callback, when its empty or not callable, mark as no wizard.
if ( ! isset( $steps[ $step ]['callback'] ) || ! is_callable( $steps[ $step ]['callback'] ) ) {
/* translators: provider's title */
return $this->get_empty_wizard( sprintf( __( 'No Settings available for %s', 'hustle' ), $this->get_title() ) );
}
$wizard = call_user_func( $steps[ $step ]['callback'], $submitted_data, $is_submit, $module_id );
// A wizard to be able to processed by our application need to has at least `html`
// which will be rendered or `redirect` which will be the url for redirect user to go to.
if ( ! isset( $wizard['html'] ) && ! isset( $wizard['redirect'] ) ) {
/* translators: provider's title */
return $this->get_empty_wizard( sprintf( __( 'No Settings available for %s', 'hustle' ), $this->get_title() ) );
}
// Add 'hustle_is_submit' hidden input at the end.
if ( isset( $wizard['html'] ) ) {
$wizard['html'] = $wizard['html'] . $this->get_step_html_common_hidden_fields( $submitted_data );
}
$wizard['opt_in_provider_current_step'] = $step;
$wizard['opt_in_provider_count_step'] = $total_steps;
$wizard['opt_in_provider_has_next_step'] = ( ( $step + 1 ) >= $total_steps ? false : true );
$wizard['opt_in_provider_has_prev_step'] = ( $step > 0 ? true : false );
// If ['data_to_save] is set on $wizard, that would mean the provider hasn't been apdapted
// to 4.0. Save the data here if it's not updated so it keeps working.
if ( isset( $wizard['data_to_save'] ) ) {
$form_settings_instance = $this->get_provider_form_settings( $module_id );
$form_settings_instance->save_form_settings_values( $wizard['data_to_save'] );
}
// Close the modal if...
$do_close = (
// It's a submission.
! empty( $submitted_data['hustle_is_submit'] ) &&
// We're in the last step.
! $wizard['opt_in_provider_has_next_step'] &&
// And there are no errors.
( ! isset( $wizard['has_errors'] ) || ! $wizard['has_errors'] )
);
if ( $do_close ) {
$wizard['is_close'] = true;
}
$wizard_default_values = array(
'has_errors' => false,
'is_close' => false,
'notification' => array(),
'size' => 'small',
'has_back' => false,
);
foreach ( $wizard_default_values as $key => $wizard_default_value ) {
if ( ! isset( $wizard[ $key ] ) ) {
$wizard[ $key ] = $wizard_default_value;
}
}
$wizard = apply_filters( 'hustle_get_integration_form_wizard', $wizard, $this, $submitted_data, $module_id, $steps, $step );
return $wizard;
}
/**
* Gets empty wizard markup.
* Helper to display a user friendly step when no settings are available.
*
* @since 3.0.5
* @param string $notice Message to be shown.
* @return array
*/
public function get_empty_wizard( $notice ) {
$notice_markup = '
';
$notice_markup .= '
';
$notice_markup .= '
' . esc_html( $notice ) . '
';
$notice_markup .= '
';
return array(
'html' => $notice_markup,
'buttons' => array(
'close' => array(
'action' => 'close',
'data' => array(),
'markup' => '' . __( 'Close', 'hustle' ) . '',
),
),
);
}
/**
* Override this function if your provider does something with the settings values.
* Called when rendering settings form.
*
* @example transform, load from other storage ?
*
* @since 4.0.0
*
* @param array $values Settings to be retrieved.
* @return mixed
*/
public function before_get_settings_values( $values ) {
return $values;
}
/**
* Get settings value
*
* @see Hustle_Provider_Abstract::before_get_settings_values()
*
* @since 4.0.0
* @return array
*/
final public function get_settings_values() {
$provider_slug = $this->get_slug();
$values = get_option( $this->get_settings_options_name(), array() );
/**
* Filter the retrieved addon's settings values from db.
*
* @since 4.0.0
*
* @param mixed $values
*/
$values = apply_filters( 'hustle_provider_' . $provider_slug . '_get_settings_values', $values );
return $values;
}
/**
* Override this function if your provider does something with the settings values.
* Called before saving the settings values to db.
*
* @example transform, save to other storage ?
*
* @since 4.0.0
*
* @param array $values Settings to be saved.
* @return mixed
*/
public function before_save_settings_values( $values ) {
return $values;
}
/**
* Save settings value
* it's already hooked with
*
* @see Hustle_Provider_Abstract::before_save_settings_values()
*
* @since 4.0.0
* @param array $values Settings to be saved.
*/
final public function save_settings_values( $values ) {
$provider_slug = $this->get_slug();
/**
* Filter the settings values of the provider to be saved.
*
* `$provider_slug` is the slug of provider that will be saved.
* Example : `mailchimp`, `zapier`, `etc`
*
* @since 4.0.0
*
* @param mixed $values
*/
$values = apply_filters( 'hustle_provider_' . $provider_slug . '_save_settings_values', $values );
update_option( $this->get_settings_options_name(), $values );
}
/**
* Saves the settings for the given $global_multi_id.
*
* @since 4.0.0
* @uses Hustle_Provider_Abstract::save_settings_values()
*
* @param string $global_multi_id ID of the global instance of the provider.
* @param array $values Settings to be stored.
*/
public function save_multi_settings_values( $global_multi_id, $values ) {
$saved_settings = $this->get_settings_values();
if ( $this->is_allow_multi_on_global() ) {
$settings_to_save = array_merge(
$saved_settings,
array(
$global_multi_id => $values,
)
);
} else {
$settings_to_save = $values;
}
$this->save_settings_values( $settings_to_save );
}
/**
* Retrieves the settings for the provider's global instance.
*
* @since 4.2.0
*
* @param boolean|string $global_multi_id ID of the global instance of the provider. False if not used.
* @return array
*/
public function get_multi_settings_values( $global_multi_id = false ) {
$settings = $this->get_settings_values();
if ( $this->is_allow_multi_on_global() ) {
$settings = ( $global_multi_id && ! empty( $settings[ $global_multi_id ] ) ) ? $settings[ $global_multi_id ] : array();
}
return $settings;
}
/**
* Auto attach default admin hooks for provider
*
* @since 4.0.0
* @return bool
*/
final public function admin_hookable() {
if ( $this->is_admin_hooked ) {
return true;
}
$default_filters = array(
'hustle_provider_' . $this->get_slug() . '_save_settings_values' => array( array( $this, 'before_save_settings_values' ), 1 ),
);
if ( $this->is_connected() ) {
$default_filters[ 'hustle_provider_' . $this->get_slug() . '_save_form_settings_values' ] = array( array( $this, 'before_save_form_settings_values' ), 2 );
}
foreach ( $default_filters as $filter => $default_filter ) {
$function_to_add = $default_filter[0];
if ( is_callable( $function_to_add ) ) {
$accepted_args = $default_filter[1];
add_filter( $filter, $function_to_add, 10, $accepted_args );
}
}
$this->is_admin_hooked = true;
return true;
}
/**
* Maintain hooks on all pages for providers.
*
* @since 4.0.0
* @return bool
*/
final public function global_hookable() {
if ( $this->is_global_hooked ) {
return true;
}
$default_filters = array(
'hustle_provider_' . $this->get_slug() . '_get_settings_values' => array( array( $this, 'before_get_settings_values' ), 1 ),
);
if ( $this->is_connected() ) {
$default_filters[ 'hustle_provider_' . $this->get_slug() . '_get_form_settings_values' ] = array( array( $this, 'before_get_form_settings_values' ), 2 );
}
foreach ( $default_filters as $filter => $default_filter ) {
$function_to_add = $default_filter[0];
if ( is_callable( $function_to_add ) ) {
$accepted_args = $default_filter[1];
add_filter( $filter, $function_to_add, 10, $accepted_args );
}
}
$this->is_global_hooked = true;
return true;
}
/**
* Delete specific WP options for the current provider
*
* @since 4.0.1
*/
public function remove_wp_options() {
}
/**
* Gets the provider's data.
* General function to get the provider's details from database based on a module_id and field key.
* This method required an instance of Hustle_Module_Model. Now it accepts the module_id in order to prevent
* third-party integrations from having to use new Hustle_Module_Model( $module_id ) just to use this method.
* -Helper.
*
* @param int|Hustle_Module_Model $module_id The ID of the module from which the data will be retrieved.
* @param string $field The field name in which the requested data is stored.
* @param string $slug The slug of the provider which data is retrieved.
*
* @return string
*/
public static function get_provider_details( $module_id, $field, $slug ) {
$details = '';
if ( is_object( $module_id ) && $module_id instanceof Hustle_Module_Model ) {
$module = $module_id;
} else {
if ( ! ( $module_id instanceof Hustle_Module_Model ) || 0 === (int) $module_id ) {
return $details;
}
$module = new Hustle_Module_Model( $module_id );
if ( is_wp_error( $module ) ) {
return $details;
}
}
if ( ! is_null( $module->content->email_services )
&& isset( $module->content->email_services[ $slug ] )
&& isset( $module->content->email_services[ $slug ][ $field ] ) ) {
$details = $module->content->email_services[ $slug ][ $field ];
}
return $details;
}
/**
* Process the return value of an external redirect.
* Also, return the behavior to have in the global integrations page.
* Useful for handling oAuth.
*
* @since 4.0.2
*
* @return array
*/
public function process_external_redirect() {
return array();
}
/**
* Updates provider's db option with the new value.
*
* @uses update_option
* @param string $option_key Name of the provider's option to be stored.
* @param mixed $option_value Value to be stored.
* @return bool
*/
public function update_provider_option( $option_key, $option_value ) {
return update_option( $this->get_slug() . '_' . $option_key, $option_value );
}
/**
* Retrieves provider's option from db.
*
* @uses get_option
* @param string $option_key Name of the option to retrieve.
* @param mixed $default Value to return if the option wasn't found.
* @return mixed
*/
public function get_provider_option( $option_key, $default ) {
return get_option( $this->get_slug() . '_' . $option_key, $default );
}
/**
* Delete provider's option from db.
*
* @since 4.0.1
* @uses delete_option
* @param string $option_key Name of the option to be deleted.
* @return bool
*/
public function delete_provider_option( $option_key ) {
return delete_option( $this->get_slug() . '_' . $option_key );
}
/**
* Like form_settings_wizards(), but for global settings.
* Should be overridden in order to show a wizard in the global settings.
*
* @since 4.0.0
* @return array
*/
public function settings_wizards() {
return array();
}
/**
* Get a stored setting.
* Handles global_multi_id if the id is passed.
*
* @since 4.0.0
*
* @param string $setting_name Name of the setting to be retrieved.
* @param mixed $default Value to return if the setting wasn't found.
* @param string $global_multi_id ID of the global instance of the provider.
* @return mixed
*/
public function get_setting( $setting_name, $default = false, $global_multi_id = false ) {
$setting_values = $this->get_settings_values();
$retrieved_setting = $default;
if ( $global_multi_id ) {
if ( isset( $setting_values[ $global_multi_id ] ) ) {
$account = $setting_values[ $global_multi_id ];
if ( isset( $account[ $setting_name ] ) ) {
$retrieved_setting = $account[ $setting_name ];
}
}
} else {
if ( isset( $setting_values[ $setting_name ] ) ) {
$retrieved_setting = $setting_values[ $setting_name ];
}
}
return $retrieved_setting;
}
/**
* Get the first found global actie connection.
*
* @since 4.0.0
* @return false|Hustle_Provider_Abstract
*/
public function find_one_global_active_connection() {
$setting_values = $this->get_settings_values();
foreach ( $setting_values as $multi_id => $setting ) {
if ( true === $this->settings_are_completed( $multi_id ) ) {
return $setting;
}
}
return false;
}
/**
* Override this function to generate your multiple id for form settings.
* Default is uniqid.
*
* @since 4.0.0
* @return string
*/
public function generate_multi_id() {
return uniqid( '', true );
}
/**
* Get an array with the id of the multiple instances of a provider in a module.
*
* @since 4.0.0
*
* @param string $module_id ID of the module.
* @return array
*/
private function get_form_settings_multi_ids( $module_id ) {
$addon_slug = $this->get_slug();
$addon = $this;
$multi_ids = array();
$form_settings_instance = $this->get_provider_form_settings( $module_id );
if ( $this->is_allow_multi_on_form() && ! is_null( $form_settings_instance ) && $form_settings_instance instanceof Hustle_Provider_Form_Settings_Abstract ) {
$multi_ids = $form_settings_instance->get_multi_ids();
}
return $multi_ids;
}
/**
* Get the globally connected accounts of this integration.
* Returned as an array such as
* (
* array(
* 'id' => {account ID},
* 'label' => {account name}
* ),
* array(
* 'id' => {account 2 ID},
* 'label' => {account 2 name}
* )
* )
*
* @since 4.0.0
* @return array
*/
public function get_global_multi_ids() {
$multi_ids = array();
$saved_settings = $this->get_settings_values();
foreach ( $saved_settings as $key => $value ) {
$multi_ids[] = array(
'id' => $key,
// If 'name' exists, use it instead.
'label' => isset( $value['name'] ) ? $value['name'] : $key,
);
}
return $multi_ids;
}
/**
* Get existing global multi id or generate a new one
*
* @param array $submitted_data Submitted data.
* @return string
*/
public function get_global_multi_id( $submitted_data ) {
$id = isset( $submitted_data['global_multi_id'] ) ? $submitted_data['global_multi_id'] : $this->generate_multi_id();
return $id;
}
/**
* Get the current data for the integration.
* If not submitted, get it from the stored settings.
* Handles multi_id settings.
*
* @since 4.0.0
*
* @param array $current_data Data that's currently stored.
* @param array $submitted_data Incoming data.
* @return array
*/
protected function get_current_data( $current_data, $submitted_data ) {
$global_multi_id = isset( $submitted_data['global_multi_id'] ) ? $submitted_data['global_multi_id'] : false;
$saved_settings = $this->get_settings_values();
foreach ( $current_data as $key => $current_field ) {
if ( isset( $submitted_data[ $key ] ) ) {
$current_data[ $key ] = $submitted_data[ $key ];
} elseif ( isset( $saved_settings[ $key ] ) && ! $this->is_allow_multi_on_global() ) {
$current_data[ $key ] = $saved_settings[ $key ];
} elseif ( $global_multi_id && isset( $saved_settings[ $global_multi_id ][ $key ] ) ) {
$current_data[ $key ] = $saved_settings[ $global_multi_id ][ $key ];
}
}
return $current_data;
}
/**
* Get hidden fields that are common among the providers.
*
* @since 4.0.0
*
* @param array $submitted_data Submitted data.
* @return string
*/
protected function get_step_html_common_hidden_fields( $submitted_data ) {
$options = array(
array(
'name' => 'hustle_is_submit',
'type' => 'hidden',
'value' => '1',
),
);
if ( $this->is_allow_multi_on_form() ) {
$options[] = array(
'name' => 'multi_id',
'type' => 'hidden',
'value' => isset( $submitted_data['multi_id'] ) ? $submitted_data['multi_id'] : $this->generate_multi_id(),
);
}
if ( $this->is_allow_multi_on_global() ) {
$options[] = array(
'name' => 'global_multi_id',
'type' => 'hidden',
'value' => isset( $submitted_data['global_multi_id'] ) ? $submitted_data['global_multi_id'] : $this->generate_multi_id(),
);
}
$html = Hustle_Provider_Utils::get_html_for_options( $options );
$html = apply_filters( 'hustle_providers_admin_add_common_hidden_fields', $html );
return $html;
}
/**
* In version 3.0 provider details like API key and URL were stored at module level,
* now they are stored globally to avoid duplication.
*
* This method addresses this difference.
*
* @param Hustle_Module_Model $module Current module.
* @param Object $old_module Old module.
*
* @return bool
*/
public function migrate_30( $module, $old_module ) {
$v3_provider = ! empty( $old_module->meta['content']['email_services'][ $this->get_slug() ] )
? $old_module->meta['content']['email_services'][ $this->get_slug() ]
: false;
if ( empty( $v3_provider ) || $this->get_30_provider_mappings() === false ) {
// Nothing to migrate.
return false;
}
$v3_provider_active = '1' === $v3_provider['enabled'];
// If the provider doesn't already exist globally, add it.
$global_multi_id = $this->get_30_migrated_provider( $v3_provider );
if ( empty( $global_multi_id ) ) {
$global_multi_id = $this->generate_multi_id();
$this->save_multi_settings_values(
$global_multi_id,
$this->map_30_provider( $v3_provider )
);
// Activate the addon.
Hustle_Providers::get_instance()->activate_addon( $this->get_slug() );
}
// Link the provider to the module.
if ( $v3_provider_active ) {
$module_provider_link = $this->strip_30_global_provider_settings( $v3_provider );
$module_provider_link['selected_global_multi_id'] = $global_multi_id;
$module->set_provider_settings( $this->get_slug(), $module_provider_link );
}
return true;
}
/**
* Map the provider's field from the old settings to the new ones.
*
* @since 4.0.0
* @param array $v3_provider Old settings of the provider.
*/
private function map_30_provider( $v3_provider ) {
$v4_provider = array();
$mappings = $this->get_30_provider_mappings();
foreach ( $mappings as $v3_index => $v4_index ) {
if ( isset( $v3_provider[ $v3_index ] ) ) {
$v4_provider[ $v4_index ] = $v3_provider[ $v3_index ];
}
}
return $v4_provider;
}
/**
* Gets the provider's map for the 3.x to 4.x migration.
*
* @since 4.0.0
* @return false|array
*/
protected function get_30_provider_mappings() {
return false;
}
/**
* If a provider has already been migrated from 3.0 this method will return its id.
*
* @param array $v3_provider Old settings of the provider.
*
* @return bool|string Global multi ID
*/
private function get_30_migrated_provider( $v3_provider ) {
$v40_providers = $this->get_settings_values();
$mapped_40_provider = $this->map_30_provider( $v3_provider );
foreach ( $v40_providers as $global_multi_id => $v40_provider ) {
if ( $v40_provider === $mapped_40_provider ) {
return $global_multi_id;
}
}
return false;
}
/**
* Strips unused old settings for the provider.
*
* @since 4.0.0
*
* @param array $v3_provider Old provider's settings.
* @return array
*/
private function strip_30_global_provider_settings( $v3_provider ) {
$copy = array();
$global_provider_settings = array_merge(
array( 'enabled', 'optin_provider_name', 'desc' ),
array_keys( $this->get_30_provider_mappings() )
);
foreach ( $v3_provider as $item => $value ) {
if ( in_array( $item, $global_provider_settings, true ) ) {
continue;
}
$copy[ $item ] = $value;
}
return $copy;
}
/**
* If a provider fails to connect,
* returns a generic message.
*
* @since 4.0.0
*
* @return string error message
*/
protected function provider_connection_falied() {
/* translators: provider's title */
$error_message = sprintf( __( "We couldn't connect to your %s account. Please resolve the errors below and try again.", 'hustle' ), $this->title );
return $error_message;
}
}