logo = $assets.'/images/fluent-support-color-logo.png'; $this->description = __('Create Support Ticket From Your Form Submission in FluentSupport', 'fluent-support'); $this->registerAdminHooks(); add_filter('fluentform/notifying_async_fluent_support', '__return_false'); } public function pushIntegration($integrations, $formId) { $integrations[$this->integrationKey] = [ 'title' => $this->title . ' Integration', 'logo' => $this->logo, 'is_active' => $this->isConfigured(), 'configure_title' => __('Configuration required!', 'fluent-support'), 'global_configure_url' => '#', 'configure_message' => __('FluentSupport is not configured yet! Please configure your FluentSupport api first', 'fluent-support'), 'configure_button_text' => __('Set FluentSupport', 'fluent-support') ]; return $integrations; } public function getIntegrationDefaults($settings, $formId) { return [ 'name' => '', 'first_name' => '', 'last_name' => '', 'email' => '', 'list_id' => '', // this is the business ID 'ticket_title' => '', 'ticket_body' => '', 'client_priority' => '', 'attachments' => '', 'product_id' => '', 'product_id_selection_type' => 'simple', 'product_routers' => [], 'customer_other_fields' => [ [ 'item_value' => '', 'label' => '' ] ], 'conditionals' => [ 'conditions' => [], 'status' => false, 'type' => 'all' ], 'enabled' => true ]; } public function getSettingsFields($settings, $formId) { $fieldOptions = []; foreach (Customer::mappables() as $key => $column) { $fieldOptions[$key] = $column; } return [ 'fields' => [ [ 'key' => 'name', 'label' => __('Feed Name', 'fluent-support'), 'required' => true, 'placeholder' => __('Your Feed Name', 'fluent-support'), 'component' => 'text' ], [ 'key' => 'list_id', 'label' => __('Business', 'fluent-support'), 'placeholder' => __('Select Business', 'fluent-support'), 'tips' => __('Select the Business you would like to add your Support Ticket to.', 'fluent-support'), 'component' => 'select', 'required' => true, 'options' => $this->geMailBoxes(), ], [ 'key' => 'product_id', 'require_list' => false, 'label' => __('Product', 'fluent-support'), 'placeholder' => __('Select Support Product', 'fluent-support'), 'component' => 'selection_routing', 'simple_component' => 'select', 'routing_input_type' => 'select', 'routing_key' => 'product_id_selection_type', 'settings_key' => 'product_routers', 'is_multiple' => false, 'labels' => [ 'choice_label' => __('Enable Dynamic Product Selection', 'fluent-support'), 'input_label' => '', 'input_placeholder' => __('Set Product', 'fluent-support') ], 'options' => $this->getProducts() ], [ 'key' => 'ticket_title', 'require_list' => false, 'label' => __('Ticket Title', 'fluent-support'), 'placeholder' => __('Ticket Title', 'fluent-support'), 'component' => 'value_text' ], [ 'key' => 'ticket_content', 'require_list' => false, 'label' => __('Ticket Content', 'fluent-support'), 'placeholder' => __('Ticket Content', 'fluent-support'), 'component' => 'value_textarea' ], [ 'key' => 'ticket_attachments', 'require_list' => false, 'label' => __('Ticket Attachments', 'fluent-support'), 'Placeholder' => __('Ticket Attachments', 'fluent-support'), 'tips' => __('Please input your file upload or image upload field shortcode here', 'fluent-support'), 'component' => 'value_text' ], [ 'key' => 'client_priority', 'require_list' => false, 'label' => __('Ticket Priority', 'fluent-support'), 'Placeholder' => __('Ticket Priority', 'fluent-support'), 'tips' => __('Make sure form field values match with Fluent Support priorities', 'fluent-support'), 'component' => 'value_text' ], $this->getCustomField(), //Getting Fluent Support Custom Field To Map [ 'component' => 'html_info', 'html_info' => '

' . __('Please provide the ticket provider info. If user is logged in then it will use that info. For Public users you can set your customer info', 'fluent-support') . '

' ], [ 'key' => 'CustomerFields', 'require_list' => false, 'label' => __('Customer Data', 'fluent-support'), 'tips' => __('Please Map Your Customer Data for this form. If your customer already logged in you can leave this', 'fluent-support'), 'component' => 'map_fields', 'field_label_remote' => __('Support Customer Field', 'fluent-support'), 'field_label_local' => __('Form Field', 'fluent-support'), 'primary_fileds' => [ [ 'key' => 'email', 'label' => __('Email Address', 'fluent-support'), 'required' => true, 'input_options' => 'emails' ], [ 'key' => 'first_name', 'label' => __('First Name', 'fluent-support') ], [ 'key' => 'last_name', 'label' => __('Last Name', 'fluent-support') ] ] ], [ 'key' => 'customer_other_fields', 'require_list' => false, 'label' => __('Customer Other Fields', 'fluent-support'), 'tips' => __('Select which Fluent Forms fields pair with their
respective Fluent Support fields.', 'fluent-support'), 'field_label_remote' => __('Fluent Support Field', 'fluent-support'), 'field_label_local' => __('Form Field', 'fluent-support'), 'component' => 'dropdown_many_fields', 'options' => $fieldOptions ], ], 'button_require_list' => false, 'integration_title' => $this->title ]; } private function geMailBoxes() { $items = MailBox::all(); $formattedItems = []; foreach ($items as $item) { $formattedItems[strval($item->id)] = $item->name; } return $formattedItems; } private function getProducts() { $products = Product::all(); $formattedProducts = []; foreach ($products as $product) { $formattedProducts[strval($product->id)] = $product->title; } return $formattedProducts; } private function getCustomField() { $customFields = apply_filters('fluent_support/ticket_custom_fields', []); $fieldToExclude = apply_filters('fluent_support/custom_field_types', []); if(empty($customFields)){ return[ 'component' => 'html_info', 'html_info' => '' ]; } $fields = []; foreach ($customFields as $customFieldKey=>$customFieldValue) { if(in_array($customFieldValue['type'], array_keys($fieldToExclude))){ unset($customFieldValue); } $fields[] = [ 'key' => $customFieldValue['slug'], 'label' => $customFieldValue['label'] ]; } $fields = array_map('array_filter', $fields); $fields = array_filter( $fields ); return [ 'key' => 'TicketCustomFields', 'require_list' => false, 'label' => __('Ticket Custom Fields', 'fluent-support'), 'tips' => __('Please Map Your Ticket Custom Field Data for this form.', 'fluent-support'), 'component' => 'map_fields', 'field_label_remote' => __('Fluent Support Custom Field', 'fluent-support'), 'field_label_local' => __('Form Field', 'fluent-support'), 'primary_fileds' => $fields ]; } public function getMergeFields($list, $listId, $formId) { return []; } public function notify($feed, $formData, $entry, $form) { $data = $feed['processedValues']; if (!empty($data['email']) && !is_email($data['email'])) { $data['email'] = Arr::get($formData, $data['email']); } $ticketCustomField = array_filter($data, function($key) { return strpos($key, 'cf_') === 0; }, ARRAY_FILTER_USE_KEY); $customFields = apply_filters('fluent_support/ticket_custom_fields', []); foreach($customFields as $key => $field){ $type = $field['type']; $slug = $field['slug']; if(!isset($ticketCustomField[$slug])) { continue; } if( $type=='checkbox' && array_key_exists($slug, $ticketCustomField)) { $value = Arr::get($ticketCustomField, $slug, ''); $ticketCustomField[$slug] = $value ? explode(',', (string)$value) : []; } else { $ticketCustomField[$slug] = Arr::get($ticketCustomField, $slug); } } $ticketData = [ 'product_source' => 'local', 'mailbox_id' => Arr::get($data, 'list_id'), 'title' => sanitize_text_field(wp_unslash(Arr::get($data, 'ticket_title'))), 'content' => wp_unslash(wp_kses_post(Arr::get($data, 'ticket_content'))), 'attachments' => sanitize_text_field(Arr::get($data, 'ticket_attachments')), 'client_priority' => strtolower(sanitize_text_field(Arr::get($data, 'client_priority', ''))), 'priority' => strtolower(sanitize_text_field(Arr::get($data, 'client_priority', ''))), 'custom_fields' => $ticketCustomField, 'source' => 'web' ]; $selectedProductArray = (array) $this->getSelectedTagIds($data, $formData, 'product_id', 'product_id_selection_type', 'product_routers'); if($selectedProductArray) { $selectedProduct = $selectedProductArray[0]; $ticketData['product_id'] = $selectedProduct; } $customerData = Arr::only($data, ['first_name', 'last_name', 'email']); foreach (Arr::get($data, 'customer_other_fields') as $field) { if ($field['item_value']) { $customerData[$field['label']] = $field['item_value']; } } $user = get_user_by('ID', get_current_user_id()); if(!$user) { $user = get_user_by('email', $customerData['email']); } if($user) { $customerData['email'] = $user->user_email; $customerData['user_id'] = $user->ID; } if(empty($customerData['email'])) { do_action('fluentform/log_data', [ 'title' => $feed['settings']['name'], 'status' => 'failed', 'description' => __('Support ticket creation failed, because no valid customer email found', 'fluent-support'), 'parent_source_id' => $form->id, 'source_id' => $entry->id, 'component' => $this->integrationKey, 'source_type' => 'submission_item' ]); return false; } $customerData['last_ip_address'] = $entry->ip; $customer = Customer::maybeCreateCustomer($customerData); // Don't create a ticket if customer is blocked if($this->isBlockedCustomer($customerData['email'])) { do_action('fluentform/log_data', [ 'title' => $feed['settings']['name'], 'status' => 'failed', 'description' => __('Support ticket creation failed, because customer email is blocked', 'fluent-support'), 'parent_source_id' => $form->id, 'source_id' => $entry->id, 'component' => $this->integrationKey, 'source_type' => 'submission_item' ]); return false; } $ticketData['customer_id'] = $customer->id; $ticketData = apply_filters('fluent_support/create_ticket_data', $ticketData, $customer); do_action('fluent_support/before_ticket_create', $ticketData, $customer); $ticket = Ticket::create($ticketData); if(defined('FLUENTSUPPORTPRO') && !empty($ticketData['custom_fields'])) { $ticket->syncCustomFields($ticketData['custom_fields']); /* * This custom_fields is causing issues in all webhook to where we called $ticket->save() * As we are calling $ticket->syncCustomFields() above, we don't need this anymore * TODO: need to remove this line in future */ //$ticket->custom_fields = $ticket->customData(); } do_action('fluent_support/ticket_created', $ticket, $customer); do_action('fluentform/log_data', [ 'title' => $feed['settings']['name'], 'status' => 'success', // translators: %d is the ticket ID number 'description' => sprintf(__('Support ticket has been created at Fluent Support. Ticket ID: %d', 'fluent-support'), $ticket->id), 'parent_source_id' => $form->id, 'source_id' => $entry->id, 'component' => $this->integrationKey, 'source_type' => 'submission_item' ]); if ($ticketData['attachments']) { $attachments = is_array($ticketData['attachments']) ? $ticketData['attachments'] : explode(',', $ticketData['attachments']); $uploadDir = wp_upload_dir(); foreach ($attachments as $attachment) { $attachment = trim($attachment); if (empty($attachment)) { continue; } $isMediaLibrary = false; $attachmentId = null; // Try to get attachment ID if it's a media library URL $attachmentId = attachment_url_to_postid($attachment); if ($attachmentId) { $isMediaLibrary = true; } try { if ($isMediaLibrary) { $filePath = get_attached_file($attachmentId); if (!$filePath) { continue; } $fileName = basename($filePath); $fileType = get_post_mime_type($attachmentId); $fullUrl = wp_get_attachment_url($attachmentId); } else { $fileName = basename($attachment); $filePath = $uploadDir['basedir'] . FLUENTFORM_UPLOAD_DIR . '/' . $fileName; $fileInfo = wp_check_filetype($filePath); $fileType = (!empty($fileInfo['type'])) ? $fileInfo['type'] : ''; $fullUrl = $attachment; } if (file_exists($filePath)) { try { Attachment::create([ 'ticket_id' => $ticket->id, 'file_path' => sanitize_text_field($filePath), 'full_url' => sanitize_url($fullUrl), 'title' => sanitize_text_field($fileName), 'person_id' => $customer->id, 'file_type' => sanitize_text_field($fileType), 'is_media_library' => $isMediaLibrary, 'attachment_id' => $attachmentId ]); } catch (\Exception $e) { } } } catch (\Exception $e) { continue; } } $ticket->load('attachments'); } return true; } public function isConfigured() { return true; } public function isEnabled() { return true; } // check if customer is blocked or not private function isBlockedCustomer($customerEmail) { $customer = Customer::where('email', $customerEmail)->first(); if('inactive' == $customer->status || !$customer->status) { return true; } return false; } }