213 lines
8.4 KiB
PHP
213 lines
8.4 KiB
PHP
<?php
|
||
/**
|
||
* Plugin Name: Gravity Forms to FreeScout
|
||
* Description: 表单提交后通过 FreeScout API 创建工单(feibisi 自维护,替代 freescout.net/neoboffin 付费插件的免费实现)。
|
||
* Version: 1.0.0
|
||
* Author: feibisi
|
||
* Requires Plugins: gravityforms
|
||
* Text Domain: gravityforms-freescout
|
||
*/
|
||
|
||
if (!defined('ABSPATH')) {
|
||
exit;
|
||
}
|
||
|
||
define('GFFS_VERSION', '1.0.0');
|
||
define('GFFS_OPT', 'gffs_settings');
|
||
|
||
add_action('admin_menu', function () {
|
||
add_options_page(
|
||
'Gravity Forms → FreeScout',
|
||
'GF → FreeScout',
|
||
'manage_options',
|
||
'gffs-settings',
|
||
'gffs_render_settings_page'
|
||
);
|
||
});
|
||
|
||
add_action('admin_init', function () {
|
||
register_setting('gffs_settings_group', GFFS_OPT, [
|
||
'type' => 'array',
|
||
'sanitize_callback' => 'gffs_sanitize_settings',
|
||
'default' => [],
|
||
]);
|
||
});
|
||
|
||
function gffs_sanitize_settings($input) {
|
||
$out = [];
|
||
$out['api_url'] = isset($input['api_url']) ? esc_url_raw(rtrim($input['api_url'], '/')) : '';
|
||
$out['api_key'] = isset($input['api_key']) ? sanitize_text_field($input['api_key']) : '';
|
||
$out['mailbox_id'] = isset($input['mailbox_id']) ? absint($input['mailbox_id']) : 1;
|
||
$out['enabled_forms'] = isset($input['enabled_forms']) ? array_map('absint', (array) $input['enabled_forms']) : [];
|
||
$out['email_field_id'] = isset($input['email_field_id']) ? sanitize_text_field($input['email_field_id']) : '';
|
||
$out['subject_prefix'] = isset($input['subject_prefix']) ? sanitize_text_field($input['subject_prefix']) : '[网站表单]';
|
||
return $out;
|
||
}
|
||
|
||
function gffs_get_settings() {
|
||
$s = get_option(GFFS_OPT, []);
|
||
return wp_parse_args(is_array($s) ? $s : [], [
|
||
'api_url' => 'https://support.weixiaoduo.com',
|
||
'api_key' => '',
|
||
'mailbox_id' => 1,
|
||
'enabled_forms' => [],
|
||
'email_field_id' => '',
|
||
'subject_prefix' => '[网站表单]',
|
||
]);
|
||
}
|
||
|
||
function gffs_render_settings_page() {
|
||
if (!current_user_can('manage_options')) {
|
||
return;
|
||
}
|
||
$s = gffs_get_settings();
|
||
$forms = [];
|
||
if (class_exists('GFAPI')) {
|
||
$forms = GFAPI::get_forms(true);
|
||
}
|
||
?>
|
||
<div class="wrap">
|
||
<h1>Gravity Forms → FreeScout</h1>
|
||
<p>提交表单后调用 FreeScout REST API 创建工单。需要 FreeScout 已安装 <strong>API & Webhooks</strong> 模块。</p>
|
||
<form method="post" action="options.php">
|
||
<?php settings_fields('gffs_settings_group'); ?>
|
||
<table class="form-table" role="presentation">
|
||
<tr>
|
||
<th><label for="gffs_api_url">FreeScout URL</label></th>
|
||
<td><input name="<?php echo esc_attr(GFFS_OPT); ?>[api_url]" id="gffs_api_url" type="url" class="regular-text" value="<?php echo esc_attr($s['api_url']); ?>" placeholder="https://support.example.com"></td>
|
||
</tr>
|
||
<tr>
|
||
<th><label for="gffs_api_key">API Key</label></th>
|
||
<td><input name="<?php echo esc_attr(GFFS_OPT); ?>[api_key]" id="gffs_api_key" type="text" class="regular-text" value="<?php echo esc_attr($s['api_key']); ?>" autocomplete="off"></td>
|
||
</tr>
|
||
<tr>
|
||
<th><label for="gffs_mailbox_id">Mailbox ID</label></th>
|
||
<td><input name="<?php echo esc_attr(GFFS_OPT); ?>[mailbox_id]" id="gffs_mailbox_id" type="number" min="1" value="<?php echo esc_attr($s['mailbox_id']); ?>"> <span class="description">默认 1(薇晓朵客服)</span></td>
|
||
</tr>
|
||
<tr>
|
||
<th><label for="gffs_subject_prefix">主题前缀</label></th>
|
||
<td><input name="<?php echo esc_attr(GFFS_OPT); ?>[subject_prefix]" id="gffs_subject_prefix" type="text" class="regular-text" value="<?php echo esc_attr($s['subject_prefix']); ?>"></td>
|
||
</tr>
|
||
<tr>
|
||
<th>启用的表单</th>
|
||
<td>
|
||
<?php if (!$forms) : ?>
|
||
<p class="description">未找到 Gravity Forms 表单。</p>
|
||
<?php else : ?>
|
||
<?php foreach ($forms as $form) :
|
||
$id = (int) $form['id'];
|
||
$checked = in_array($id, $s['enabled_forms'], true) ? 'checked' : '';
|
||
?>
|
||
<label style="display:block;margin:4px 0">
|
||
<input type="checkbox" name="<?php echo esc_attr(GFFS_OPT); ?>[enabled_forms][]" value="<?php echo $id; ?>" <?php echo $checked; ?>>
|
||
#<?php echo $id; ?> — <?php echo esc_html($form['title']); ?>
|
||
</label>
|
||
<?php endforeach; ?>
|
||
<p class="description">不勾选任何表单 = 全部表单启用。</p>
|
||
<?php endif; ?>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
<?php submit_button(); ?>
|
||
</form>
|
||
</div>
|
||
<?php
|
||
}
|
||
|
||
/**
|
||
* After GF submit → FreeScout conversation.
|
||
*/
|
||
add_action('gform_after_submission', 'gffs_after_submission', 20, 2);
|
||
|
||
function gffs_after_submission($entry, $form) {
|
||
$s = gffs_get_settings();
|
||
if (empty($s['api_url']) || empty($s['api_key'])) {
|
||
return;
|
||
}
|
||
$form_id = (int) ($form['id'] ?? 0);
|
||
if (!empty($s['enabled_forms']) && !in_array($form_id, $s['enabled_forms'], true)) {
|
||
return;
|
||
}
|
||
|
||
$email = gffs_find_email($entry, $form);
|
||
if (!$email) {
|
||
// FreeScout API requires customer_email
|
||
$email = 'form+' . $form_id . '@noreply.local';
|
||
}
|
||
|
||
$title = $form['title'] ?? ('Form #' . $form_id);
|
||
$subject = trim(($s['subject_prefix'] ? $s['subject_prefix'] . ' ' : '') . $title);
|
||
$body = gffs_build_body($entry, $form);
|
||
|
||
$payload = [
|
||
'mailbox_id' => (int) $s['mailbox_id'] ?: 1,
|
||
'subject' => mb_substr($subject, 0, 200),
|
||
'customer_email' => $email,
|
||
'body' => $body,
|
||
'status' => 'active',
|
||
'type' => 'email',
|
||
];
|
||
|
||
$url = rtrim($s['api_url'], '/') . '/api/v1/conversations';
|
||
$resp = wp_remote_post($url, [
|
||
'timeout' => 20,
|
||
'headers' => [
|
||
'Content-Type' => 'application/json',
|
||
'Accept' => 'application/json',
|
||
'X-Api-Key' => $s['api_key'],
|
||
],
|
||
'body' => wp_json_encode($payload),
|
||
]);
|
||
|
||
if (is_wp_error($resp)) {
|
||
error_log('[GFFS] FreeScout error: ' . $resp->get_error_message());
|
||
return;
|
||
}
|
||
$code = wp_remote_retrieve_response_code($resp);
|
||
$body_r = wp_remote_retrieve_body($resp);
|
||
if ($code < 200 || $code >= 300) {
|
||
error_log('[GFFS] FreeScout HTTP ' . $code . ' ' . substr($body_r, 0, 300));
|
||
}
|
||
}
|
||
|
||
function gffs_find_email($entry, $form) {
|
||
foreach ($form['fields'] as $field) {
|
||
$type = is_object($field) ? $field->type : ($field['type'] ?? '');
|
||
$id = is_object($field) ? $field->id : ($field['id'] ?? '');
|
||
if ($type === 'email' && !empty($entry[$id])) {
|
||
return sanitize_email($entry[$id]);
|
||
}
|
||
}
|
||
// common: field 1 is email
|
||
foreach ($entry as $k => $v) {
|
||
if (is_string($v) && is_email($v)) {
|
||
return sanitize_email($v);
|
||
}
|
||
}
|
||
return '';
|
||
}
|
||
|
||
function gffs_build_body($entry, $form) {
|
||
$lines = [];
|
||
$lines[] = '<p><strong>Gravity Form:</strong> ' . esc_html($form['title'] ?? '') . ' (#' . (int) $form['id'] . ')</p>';
|
||
$lines[] = '<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse">';
|
||
foreach ($form['fields'] as $field) {
|
||
$type = is_object($field) ? $field->type : ($field['type'] ?? '');
|
||
$id = is_object($field) ? $field->id : ($field['id'] ?? '');
|
||
$label = is_object($field) ? $field->label : ($field['label'] ?? ('Field ' . $id));
|
||
if (in_array($type, ['html', 'section', 'page', 'captcha', 'honeypot'], true)) {
|
||
continue;
|
||
}
|
||
$val = rgar($entry, (string) $id);
|
||
if ($val === '' || $val === null) {
|
||
continue;
|
||
}
|
||
if (is_array($val)) {
|
||
$val = implode(', ', $val);
|
||
}
|
||
$lines[] = '<tr><th align="left">' . esc_html($label) . '</th><td>' . nl2br(esc_html((string) $val)) . '</td></tr>';
|
||
}
|
||
$lines[] = '</table>';
|
||
$lines[] = '<p style="color:#888;font-size:12px">via Gravity Forms to FreeScout ' . GFFS_VERSION . '</p>';
|
||
return implode("\n", $lines);
|
||
}
|