$user_email,
'api_key' => $api_key
);
}
class ADFOIN_Nutshell {
private static $instance;
protected $user_email = '';
protected $api_key = '';
public static function get_instance() {
if (empty(self::$instance)) {
self::$instance = new self;
}
return self::$instance;
}
public function __construct() {
$this->set_credentials();
add_filter('adfoin_action_providers', array($this, 'adfoin_nutshell_actions'), 10, 1);
add_filter('adfoin_settings_tabs', array($this, 'adfoin_nutshell_settings_tab'), 10, 1);
add_action('adfoin_settings_view', array($this, 'adfoin_nutshell_settings_view'), 10, 1);
add_action('wp_ajax_adfoin_get_nutshell_fields', array($this, 'get_fields'));
add_action('adfoin_action_fields', array($this, 'action_fields'), 10, 1);
add_action('wp_ajax_adfoin_get_nutshell_owners', array($this, 'get_owners'));
// Account Manager AJAX hooks
add_action( 'wp_ajax_adfoin_get_nutshell_credentials', array($this, 'get_credentials_ajax') );
add_action( 'wp_ajax_adfoin_save_nutshell_credentials', array($this, 'save_credentials_ajax') );
add_action( 'wp_ajax_adfoin_get_nutshell_credentials_list', array($this, 'get_credentials_list_ajax') );
}
public function get_credentials_ajax() {
if ( ! class_exists( 'ADFOIN_Account_Manager' ) ) {
require_once plugin_dir_path( __FILE__ ) . '../../includes/class-adfoin-account-manager.php';
}
ADFOIN_Account_Manager::ajax_get_credentials( 'nutshell' );
}
public function save_credentials_ajax() {
if ( ! class_exists( 'ADFOIN_Account_Manager' ) ) {
require_once plugin_dir_path( __FILE__ ) . '../../includes/class-adfoin-account-manager.php';
}
ADFOIN_Account_Manager::ajax_save_credentials( 'nutshell', array( 'user_email', 'api_key' ) );
}
public function get_credentials_list_ajax() {
if ( ! wp_verify_nonce( $_POST['_nonce'], 'advanced-form-integration' ) ) {
return;
}
if ( ! class_exists( 'ADFOIN_Account_Manager' ) ) {
require_once plugin_dir_path( __FILE__ ) . '../../includes/class-adfoin-account-manager.php';
}
$fields = array(
array( 'name' => 'user_email', 'mask' => false ),
array( 'name' => 'api_key', 'mask' => true ),
);
ADFOIN_Account_Manager::ajax_get_credentials_list( 'nutshell', $fields );
}
public function get_owners() {
adfoin_verify_nonce();
$cred_id = isset( $_POST['credId'] ) ? sanitize_text_field( wp_unslash( $_POST['credId'] ) ) : '';
$response = $this->request('users', 'GET', array(), array(), $cred_id);
$body = wp_remote_retrieve_body($response);
$data = json_decode($body, true);
$owners = [];
if (isset($data['users']) && !empty($data['users'])) {
foreach ($data['users'] as $user) {
$owners[$user['id']] = $user['firstName'] . ' ' . $user['lastName'];
}
}
wp_send_json_success($owners);
}
public function action_fields() {
?>
__('Nutshell CRM', 'advanced-form-integration'),
'tasks' => [
'add_contact' => __('Add Contact', 'advanced-form-integration'),
],
];
return $actions;
}
public function adfoin_nutshell_settings_tab($providers) {
$providers['nutshell'] = __('Nutshell CRM', 'advanced-form-integration');
return $providers;
}
public function adfoin_nutshell_settings_view($current_tab) {
if ($current_tab !== 'nutshell') return;
// Load Account Manager
if ( ! class_exists( 'ADFOIN_Account_Manager' ) ) {
require_once plugin_dir_path( __FILE__ ) . '../../includes/class-adfoin-account-manager.php';
}
// Migrate old settings if they exist and no new credentials exist
$option = (array) maybe_unserialize(get_option('adfoin_nutshell_keys'));
$old_user_email = isset($option['user_email']) ? $option['user_email'] : '';
$old_api_key = isset($option['api_key']) ? $option['api_key'] : '';
$existing_creds = adfoin_read_credentials( 'nutshell' );
if ( $old_user_email && $old_api_key && empty( $existing_creds ) ) {
$new_cred = array(
'id' => wp_generate_uuid4(),
'title' => 'Default Account (Legacy)',
'user_email' => $old_user_email,
'api_key' => $old_api_key
);
adfoin_save_credentials( 'nutshell', array( $new_cred ) );
}
$fields = array(
array(
'name' => 'user_email',
'label' => __( 'User Email', 'advanced-form-integration' ),
'type' => 'text',
'required' => true,
'placeholder' => __( 'Enter User Email', 'advanced-form-integration' ),
'show_in_table' => true,
),
array(
'name' => 'api_key',
'label' => __( 'API Key', 'advanced-form-integration' ),
'type' => 'text',
'required' => true,
'placeholder' => __( 'Enter API Key', 'advanced-form-integration' ),
'mask' => true,
'show_in_table' => true,
),
);
$instructions = '
- ' . __( 'Go to your Nutshell CRM account settings.', 'advanced-form-integration' ) . '
- ' . __( 'Navigate to API settings and generate an API Key.', 'advanced-form-integration' ) . '
- ' . __( 'Enter your User Email and API Key above.', 'advanced-form-integration' ) . '
- ' . __( 'Click "Add Account" and save your credentials.', 'advanced-form-integration' ) . '
';
ADFOIN_Account_Manager::render_settings_view( 'nutshell', 'Nutshell CRM', $fields, $instructions );
}
public function get_fields() {
adfoin_verify_nonce();
$task = isset($_POST['task']) ? sanitize_text_field( wp_unslash( $_POST['task'] ) ) : '';
$fields = [];
if ($task == 'add_contact') {
$account_fields = [
['key' => 'account__name', 'value' => 'Name [Account]'],
['key' => 'account__description', 'value' => 'Description [Account]'],
['key' => 'account__phone', 'value' => 'Phone [Account]'],
['key' => 'account__email', 'value' => 'Email [Account]'],
['key' => 'account__url', 'value' => 'URL [Account]'],
['key' => 'account__address_1', 'value' => 'Address 1 [Account]'],
['key' => 'account__city', 'value' => 'City [Account]'],
['key' => 'account__state', 'value' => 'State [Account]']
];
$contact_fields = [
['key' => 'contact__name', 'value' => 'Name [Contact]'],
['key' => 'contact__email', 'value' => 'Email [Contact]'],
['key' => 'contact__bio', 'value' => 'Bio [Contact]'],
['key' => 'contact__phone', 'value' => 'Phone [Contact]'],
['key' => 'contact__address_1', 'value' => 'Address 1 [Contact]'],
['key' => 'contact__city', 'value' => 'City [Contact]'],
['key' => 'contact__state', 'value' => 'State [Contact]'],
['key' => 'contact__postalCode', 'value' => 'Postal Code [Contact]'],
['key' => 'contact__country', 'value' => 'Country [Contact]'],
['key' => 'contact__url', 'value' => 'URL [Contact]'],
];
$fields = array_merge($fields, $account_fields, $contact_fields);
}
wp_send_json_success($fields);
}
public function create_account($account_data, $record, $cred_id = '') {
$response = $this->request('accounts', 'POST', $account_data, $record, $cred_id);
$response_body = json_decode(wp_remote_retrieve_body($response), true);
if (isset($response_body['accounts'], $response_body['accounts'][0], $response_body['accounts'][0]['id'])) {
return $response_body['accounts'][0]['id'];
}
return $response;
}
public function find_account($name, $cred_id = '') {
$endpoint = 'accounts?q=' . urlencode($name);
$response = $this->request($endpoint, 'GET', array(), array(), $cred_id);
if (is_wp_error($response)) {
return $response;
}
$body = wp_remote_retrieve_body($response);
$data = json_decode($body, true);
if (isset($data['accounts']) && !empty($data['accounts'])) {
if( $name == $data['accounts'][0]['name'] ) {
return $data['accounts'][0];
}
}
return null;
}
public function update_account($account_id, $account_data, $record, $cred_id = '') {
$patch_data = [];
foreach ($account_data['accounts'][0] as $field => $value) {
if (is_array($value)) {
$patch_data[] = [
'op' => 'replace',
'path' => '/accounts/0/' . $field,
'value' => $value
];
} else {
$patch_data[] = [
'op' => 'replace',
'path' => '/accounts/0/' . $field,
'value' => $value
];
}
}
$endpoint = 'accounts/' . $account_id;
$response = $this->request($endpoint, 'PATCH', $patch_data, $record, $cred_id);
return $response;
}
public function create_contact($contact_data, $record, $cred_id = '') {
$response = $this->request('contacts', 'POST', $contact_data, $record, $cred_id);
$response_body = json_decode(wp_remote_retrieve_body($response), true);
if (isset($response_body['id'])) {
return $response_body['id'];
}
return $response;
}
public function find_contact($email, $cred_id = '') {
$endpoint = 'contacts?email=' . urlencode($email);
$response = $this->request($endpoint, 'GET', array(), array(), $cred_id);
if (is_wp_error($response)) {
return $response;
}
$body = wp_remote_retrieve_body($response);
$data = json_decode($body, true);
if (isset($data['contacts']) && !empty($data['contacts'])) {
return $data['contacts'][0];
}
return null;
}
public function update_contact($contact_id, $contact_data, $record, $cred_id = '') {
$endpoint = 'contacts/' . $contact_id;
$response = $this->request($endpoint, 'PUT', $contact_data, $record, $cred_id);
return $response;
}
public function request($endpoint, $method = 'GET', $data = array(), $record = array(), $cred_id = '') {
$credentials = adfoin_nutshell_get_credentials( $cred_id );
$user_email = $credentials['user_email'];
$api_key = $credentials['api_key'];
if( !$user_email || !$api_key ) {
return new WP_Error( 'missing_credentials', 'User Email or API Key is missing' );
}
$base_url = "https://app.nutshell.com/rest/";
$url = $base_url . $endpoint;
$args = array(
'timeout' => 30,
'method' => $method,
'headers' => array(
'Content-Type' => $method === 'PATCH' ? 'application/json-patch+json' : 'application/json',
'Authorization' => 'Basic ' . base64_encode($user_email . ':' . $api_key)
),
);
if ('POST' == $method || 'PUT' == $method || 'PATCH' == $method) {
$args['body'] = wp_json_encode($data);
}
$response = wp_remote_request($url, $args);
if ($record) {
adfoin_add_to_log($response, $url, $args, $record);
}
return $response;
}
public function set_credentials() {
$option = (array) maybe_unserialize(get_option('adfoin_nutshell_keys'));
if (isset($option['user_email'])) {
$this->user_email = $option['user_email'];
}
if (isset($option['api_key'])) {
$this->api_key = $option['api_key'];
}
}
}
$nutshell = ADFOIN_Nutshell::get_instance();
add_action('adfoin_nutshell_job_queue', 'adfoin_nutshell_job_queue', 10, 1);
function adfoin_nutshell_job_queue($data) {
adfoin_nutshell_send_data($data['record'], $data['posted_data']);
}
function adfoin_nutshell_send_data($record, $posted_data) {
$record_data = json_decode($record['data'], true);
if (isset($record_data['action_data']['cl']) && adfoin_check_conditional_logic($record_data['action_data']['cl'], $posted_data)) return;
$data = $record_data['field_data'];
$cred_id = isset( $data['credId'] ) ? $data['credId'] : '';
$task = $record['task'];
$owner_id = isset($data['ownerId']) ? $data['ownerId'] : null;
$nutshell = ADFOIN_Nutshell::get_instance();
if ($task == 'add_contact') {
$parsed_account_data = array();
$parsed_contact_data = array();
$account_id = null;
$contact_id = null;
foreach ($data as $key => $value) {
$parsed_value = adfoin_get_parsed_values($value, $posted_data);
if ($parsed_value) {
if (strpos($key, 'account__') === 0) {
$parsed_account_data[substr($key, strlen('account__'))] = $parsed_value;
} elseif (strpos($key, 'contact__') === 0) {
$parsed_contact_data[substr($key, strlen('contact__'))] = $parsed_value;
}
}
}
if (!empty($parsed_account_data)) {
$account_data = [
'accounts' => [
array_filter([
'name' => isset($parsed_account_data['name']) ? $parsed_account_data['name'] : '',
'description' => isset($parsed_account_data['description']) ? $parsed_account_data['description'] : ''
])
]
];
if (isset($parsed_account_data['phone'])) {
$account_data['accounts'][0]['phones'] = [];
$account_data['accounts'][0]['phones'][] = [
'isPrimary' => true,
'name' => 'phone',
'value' => $parsed_account_data['phone']
];
}
if (isset($parsed_account_data['email'])) {
$account_data['accounts'][0]['emails'] = [];
$account_data['accounts'][0]['emails'][] = [
'value' => $parsed_account_data['email']
];
}
if (isset($parsed_account_data['url'])) {
$account_data['accounts'][0]['urls'] = [];
$account_data['accounts'][0]['urls'][] = [
'value' => $parsed_account_data['url']
];
}
if (isset($parsed_account_data['address_1']) || isset($parsed_account_data['city']) || isset($parsed_account_data['state'])) {
$account_data['accounts'][0]['addresses'] = [];
$account_data['accounts'][0]['addresses'][] = array_filter([
'isPrimary' => true,
'name' => 'address',
'value' => [
'address_1' => isset($parsed_account_data['address_1']) ? $parsed_account_data['address_1'] : '',
'city' => isset($parsed_account_data['city']) ? $parsed_account_data['city'] : '',
'state' => isset($parsed_account_data['state']) ? $parsed_account_data['state'] : ''
]
]);
}
if( $owner_id ) {
if (!isset($account_data['accounts'][0]['links'])) {
$account_data['accounts'][0]['links'] = [];
}
$account_data['accounts'][0]['links']['owner'] = $owner_id;
}
$existing_account = $nutshell->find_account($parsed_account_data['name'], $cred_id);
if ($existing_account) {
$account_id = $existing_account['id'];
$nutshell->update_account($account_id, $account_data, $record, $cred_id);
} else {
$account_id = $nutshell->create_account($account_data, $record, $cred_id);
}
}
if (!empty($parsed_contact_data)) {
$contact_data = [
'contacts' => [
array_filter([
'name' => isset($parsed_contact_data['name']) ? $parsed_contact_data['name'] : '',
'description' => isset($parsed_contact_data['bio']) ? $parsed_contact_data['bio'] : ''
])
]
];
if (isset($parsed_contact_data['phone'])) {
$contact_data['contacts'][0]['phones'] = [];
$contact_data['contacts'][0]['phones'][] = [
'isPrimary' => true,
'name' => 'phone',
'value' => [
'number' => $parsed_contact_data['phone']
]
];
}
if (isset($parsed_contact_data['email'])) {
$contact_data['contacts'][0]['emails'] = [];
$contact_data['contacts'][0]['emails'][] = [
'isPrimary' => true,
'name' => 'email',
'value' => $parsed_contact_data['email']
];
}
if (isset($parsed_contact_data['url'])) {
$contact_data['contacts'][0]['urls'] = [];
$contact_data['contacts'][0]['urls'][] = [
'isPrimary' => true,
'name' => 'url',
'value' => $parsed_contact_data['url']
];
}
if (isset($parsed_contact_data['address_1']) || isset($parsed_contact_data['city']) || isset($parsed_contact_data['state']) || isset($parsed_contact_data['postalCode']) || isset($parsed_contact_data['country'])) {
$contact_data['contacts'][0]['addresses'] = [];
$contact_data['contacts'][0]['addresses'][] = array_filter([
'isPrimary' => true,
'name' => 'address',
'address_1' => isset($parsed_contact_data['address_1']) ? $parsed_contact_data['address_1'] : '',
'city' => isset($parsed_contact_data['city']) ? $parsed_contact_data['city'] : '',
'state' => isset($parsed_contact_data['state']) ? $parsed_contact_data['state'] : '',
'postalCode' => isset($parsed_contact_data['postalCode']) ? $parsed_contact_data['postalCode'] : '',
'country' => isset($parsed_contact_data['country']) ? $parsed_contact_data['country'] : ''
]);
}
if ($account_id) {
$contact_data['contacts'][0]['links'] = [];
$contact_data['contacts'][0]['links']['accounts'] = [$account_id];
}
if( $owner_id ) {
if (!isset($contact_data['contacts'][0]['links'])) {
$contact_data['contacts'][0]['links'] = [];
}
$contact_data['contacts'][0]['links']['owner'] = $owner_id;
}
$existing_contact = $nutshell->find_contact($parsed_contact_data['email'], $cred_id);
if ($existing_contact) {
$contact_id = $existing_contact['id'];
$nutshell->update_contact($contact_id, $contact_data, $record, $cred_id);
} else {
$nutshell->create_contact($contact_data, $record, $cred_id);
}
}
}
}