| 开发者 | mksddn |
|---|---|
| 更新时间 | 2026年9月3日 15:01 |
| PHP版本: | 8.0 及以上 |
| WordPress版本: | 7.1 |
| 版权: | GPLv2 or later |
| 版权网址: | 版权信息 |
/wp-content/plugins/mksddn-forms-handler directory, or install the plugin through the WordPress plugins screen directly.[mksddn_fh_form id="form_id"] or [mksddn_fh_form slug="form-slug"] to display forms on your pages/start), then call:
https://api.telegram.org/bot{your_bot_token}/getUpdates
Look for the "chat" object in the JSON response and find the "id" field. Note: Group chat IDs are typically negative numbers.{form_title}, {date}, {time}, {datetime}, {page_url}{field:field_name} for field value, {field_label:field_name} for field labelb, i, u, s, code, pre, a
Enable "Use Custom Template" in Telegram settings and enter your template in the textarea.Yes! The plugin is designed to work with any WordPress theme. Forms are displayed using shortcodes and can be styled with CSS.
Yes, the plugin includes comprehensive security measures:
Yes! The plugin provides REST API endpoints for AJAX form submissions. Check the REST API section for details.
Yes! Enable "Accept any fields from frontend" in form settings (Advanced Settings section). This allows submitting any field names without defining them in Fields Configuration - perfect for custom forms where you control the HTML. All fields are still sanitized, but type validation is skipped. You can also use the mksddn_fh_allowed_fields filter in your theme's functions.php to dynamically allow specific fields or all fields (return ['*']).
Yes! Configure a redirect URL in form settings (Display tab). You can use:
/thank-you)
External domains are blocked by default for security. To allow external redirects, use the mksddn_fh_allowed_redirect_hosts filter to whitelist specific domains.Component-based structure following SOLID principles with clear separation of concerns: Core Components (includes/)
PostTypes - custom post types registration (mksddn_fh_forms, mksddn_fh_submits)MetaBoxes - form settings and submission data managementFormsHandler - main processing logic, REST API, per-form rate limiting, delivery orchestrationShortcodes - form rendering with AJAX functionalityAdminColumns - admin interface customizationExportHandler - CSV export with filteringSecurity - admin restrictions for submissions (blocks manual create/edit in wp-admin)SpamProtection - global rate limit, heuristics, Turnstile verificationSpamSettingsAdmin - global spam protection settings pageUtilities - helper functions and form creation utilitiesGoogleSheetsAdmin - Google Sheets settings page and OAuthAssets - asset registration and conditional enqueuingTemplate Functions - global functions for PHP template integration
Traits (includes/traits/)
TelegramFormatterTrait - HTML escaping and formatting for Telegram messages
Handlers (handlers/)
TelegramHandler - Telegram Bot API integration
GoogleSheetsHandler - Google Sheets API integrationTemplateParser - placeholder parsing for Telegram and user reply emails
Assets (assets/)
css/admin.css - Admin styles (form settings, export, Google Sheets and spam settings pages)
js/admin.js - Admin scripts (tabs, previews, user reply and trusted origins UI)js/form.js - Frontend AJAX form submission (enqueued by shortcode or template helpers)js/turnstile-loader.js - Local loader for Cloudflare Turnstile widget scriptmksddn-forms-handler/ ├── mksddn-forms-handler.php # Main plugin file ├── includes/ # Core components │ ├── class-post-types.php │ ├── class-meta-boxes.php │ ├── class-forms-handler.php │ ├── class-shortcodes.php │ ├── class-admin-columns.php │ ├── class-export-handler.php │ ├── class-security.php │ ├── class-utilities.php │ ├── class-spam-protection.php │ ├── class-spam-settings-admin.php │ ├── class-google-sheets-admin.php │ ├── class-assets.php │ ├── template-functions.php │ └── traits/ │ └── trait-telegram-formatter.php ├── handlers/ # External service handlers │ ├── class-telegram-handler.php │ ├── class-google-sheets-handler.php │ └── class-template-parser.php ├── templates/ # Template files │ ├── form-settings-meta-box.php │ └── custom-form-examples.php ├── assets/ # Static resources │ ├── css/ │ │ └── admin.css │ └── js/ │ ├── admin.js │ ├── form.js │ └── turnstile-loader.js ├── languages/ # Translations └── uninstall.php # Cleanup script
1. Shortcode (Standard) [mksddn_fh_form slug="contact-form"] Plugin automatically generates HTML form based on configuration. 2. PHP Templates (Custom Forms) Integrate pre-built forms in theme templates: Send Available Functions:
mksddn_fh_get_form_action() - get form action URLmksddn_fh_form_fields($slug) - output hidden fields (nonce, form_id, honeypot)mksddn_fh_get_form_config($slug) - get form configurationmksddn_fh_get_rest_endpoint($slug) - get REST API endpoint for AJAXmksddn_fh_form_has_files($slug) - check for file fieldsmksddn_fh_enqueue_form_script() - enqueue AJAX scriptmksddn_fh_render_turnstile($slug) - output Turnstile widget markup (when required)mksddn_fh_enqueue_turnstile() - enqueue Turnstile loader scriptmksddn_fh_form_requires_turnstile($slug) - check if form requires Turnstile
Accept Any Fields (Advanced):
For custom forms where you control field names in templates, enable "Accept any fields from frontend" in form settings (Advanced tab) to skip field validation. Stored as post meta _allow_any_fields (0 / 1). This allows submitting ANY field names without defining them in Fields Configuration. All fields are still sanitized but type validation is skipped./templates/custom-form-examples.php for detailed examples.
User Reply Email (Email Settings tab):
Optional auto-reply to the user who submitted the form. Configure in the form Email Settings tab:
_send_user_reply — enable/disable auto-reply (0 / 1)_user_reply_email_field — field name from Fields Configuration (type: email)_user_reply_type — text (template with placeholders) or html (uploaded HTML file)_user_reply_subject — reply subject with placeholders_user_reply_message — text template body_user_reply_html_template — HTML file content stored in post meta{form_title}, {date}, {time}, {datetime}, {page_url}, {field:field_name}, {field_label:field_name}.
HTML template upload: .html/.htm only, max 100 KB (filter mksddn_fh_max_html_template_size). PHP code and script tags in templates are rejected.
User reply can be the only enabled delivery channel — a successful auto-reply counts as a successful form submission. Auto-reply failure alone does not block submission when another channel succeeds; result is reported in delivery_results.user_reply_email.
3. REST API (AJAX)
Submit forms via REST API without page reload:
fetch('<?php echo mksddn_fh_get_rest_endpoint("contact-form"); ?>', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(formData)
});
Coding
Filters:
mksddn_fh_allowed_fields - Modify allowed field names for a form
add_filter('mksddn_fh_allowed_fields', function($allowed_fields, $form_id, $form_slug) {
// Allow all fields for specific form
if ($form_slug === 'my-custom-form') {
return ['*'];
}
// Add specific fields
return array_merge($allowed_fields, ['custom_field_1', 'custom_field_2']);
}, 10, 3);
mksddn_fh_allowed_redirect_hosts - Whitelist external domains for redirect URLs
add_filter('mksddn_fh_allowed_redirect_hosts', function($hosts) {
return array_merge($hosts, ['example.com', 'trusted-partner.com']);
});
mksddn_fh_max_html_template_size - Maximum size in bytes for uploaded user reply HTML templates (default: 102400)
mksddn_fh_max_template_size - Maximum Telegram custom template size in characters (default: 10000)
mksddn_forms_telegram_message - Modify the Telegram message before sending
add_filter('mksddn_forms_telegram_message', function($message, $form_data, $form_title, $fields_config) {
return $message . "\n— Sent via site";
}, 10, 4);
mksddn_fh_turnstile_verify_url - Override the Cloudflare Turnstile siteverify endpoint URL
mksddn_fh_trusted_origins_bypass - Skip trusted origins validation for a request (default: false)
add_filter('mksddn_fh_trusted_origins_bypass', function($bypass, $form_id, $mode) {
// Allow server-side proxy submissions for a specific form
if ($form_id === 123 && $mode === 'allowlist') {
return true;
}
return $bypass;
}, 10, 3);
mksddn_fh_before_submit - Block or allow submission after validation, before delivery
add_filter('mksddn_fh_before_submit', function($allowed, $form_data, $form_config) {
if (isset($form_data['email']) && str_contains($form_data['email'], 'spam.example')) {
return new WP_Error('blocked', 'Blocked');
}
return $allowed;
}, 10, 3);
mksddn_fh_is_spam - Custom spam decision when built-in heuristics are enabled (default: false)
mksddn_fh_spam_multi_select_threshold - Minimum selected options count to treat as spam (default: 7)
mksddn_fh_client_ip - Override client IP used for rate limiting and Turnstile (default: REMOTE_ADDR). Use this behind Cloudflare/a reverse proxy after you restore the real visitor IP; do not trust X-Forwarded-For from the client.
Actions:
mksddn_forms_handler_log_security - Fired when unauthorized fields are detected (hook for custom logging; no built-in log storage)
mksddn_forms_handler_log_submission - Fired when form submission is processed (hook for custom logging)
Namespace: mksddn-forms-handler/v1
/wp-json/mksddn-forms-handler/v1/formsper_page (1–100, default: 10)page (>=1, default: 1)search (string, optional)X-WP-Total, X-WP-TotalPages/wp-json/mksddn-forms-handler/v1/forms/{slug}id, slug, title, submit_url, fields (sanitized config), require_turnstile, and turnstile_site_key when Turnstile is required (never the secret key)/wp-json/mksddn-forms-handler/v1/forms/{slug}/submitmksddn_fh_hp honeypot field may be present and must be empty (spam protection).name[].unauthorized_fields erroroff)Global settings: Forms → Spam Protection. Per-form overrides: Advanced tab on each form. Global rate limit
global_rate_limited (HTTP 429)
Spam heuristics
array_of_objects, file fields, or free-text values outside configured name fieldsspam_detected (HTTP 400)
Cloudflare Turnstile
1/0 map to on/inherit)cf-turnstile-response or mksddn_fh_turnstile_response in the request bodyrequire_turnstile and turnstile_site_key when enabledmksddn_fh_render_turnstile(), mksddn_fh_enqueue_turnstile(), mksddn_fh_form_requires_turnstile()turnstile_required, turnstile_failed, turnstile_not_configuredmksddn_fh_client_ip); REMOTE_ADDR alone may be the proxy IPAdditional layer on top of nonce, honeypot, and rate limiting. Configure per form in Advanced tab. Modes
off (default) — no origin check; existing forms behave unchanged after plugin updatesame_site — accept submissions only from the WordPress site origin (home_url / site_url)allowlist — accept only origins listed in the form settings (one per line, e.g. https://www.example.com)
Headers
Origin
Referer when enabled (default on) for browser form posts without Origin
Errors
origin_not_allowed (HTTP 403) in REST and admin-post JSON responses
Notes
www, and ports are distinct origins — list each explicitly in allowlist mode
off, referer fallback on)mksddn_fh_trusted_origins_bypass for infrastructure edge casesList forms: curl -s 'https://example.com/wp-json/mksddn-forms-handler/v1/forms' Get single form: curl -s 'https://example.com/wp-json/mksddn-forms-handler/v1/forms/contact' Submit form (JSON): curl -s -X POST \ -H 'Content-Type: application/json' \ -d '{"name":"John","email":"john@example.com","message":"Hi","mksddn_fh_hp":""}' \ 'https://example.com/wp-json/mksddn-forms-handler/v1/forms/contact/submit' Submit form with files (multipart): curl -s -X POST \ -F 'name=John' \ -F 'email=john@example.com' \ -F 'attachments[]=@/path/to/file1.pdf' \ -F 'attachments[]=@/path/to/file2.png' \ 'https://example.com/wp-json/mksddn-forms-handler/v1/forms/contact/submit'
Fields are configured as JSON in the form settings. Supported types:
name - field name (required, used as form input name)label - field label displayed in forms and admin (optional, falls back to name)notification_label - custom label for Telegram/email notifications (optional, priority: notification_label → label → name)type - field type (required)required - whether field is required (boolean, default: false)options can be an array of strings or objects { "value": "...", "label": "..." }select with multiple choice, set multiple: true (shortcode renders name[])number, optional attributes: min, max, steptel, optional pattern (default server validation uses ^\+?\d{7,15}$)date/time/datetime-local, server validates formats: YYYY-MM-DD, HH:MM, YYYY-MM-DDTHH:MMallowed_extensions: Array of extensions, e.g. ["pdf","png","jpg"]max_size_mb: Maximum size per file (default: 10)max_files: Maximum files per field (default: 5)multiple: Allow multiple files[ {"name":"name","label":"Name","type":"text","required":true,"placeholder":"Your name"}, {"name":"email","label":"Email","notification_label":"Email Address","type":"email","required":true}, {"name":"phone","label":"Phone","type":"tel","pattern":"^\\+?\\d{7,15}$"}, {"name":"website","label":"Website","type":"url"}, {"name":"age","label":"Age","type":"number","min":1,"max":120,"step":1}, {"name":"birth","label":"Birth date","type":"date"}, {"name":"message","label":"Message","type":"textarea","required":true}, {"name":"agree","label":"I agree to Terms","type":"checkbox","required":true}, { "name":"services", "label":"Choose services", "type":"select", "multiple":true, "options":["seo","smm","ads"] }, { "name":"attachments", "label":"Attach files", "type":"file", "multiple":true, "allowed_extensions":["pdf","png","jpg"], "max_size_mb":10, "max_files":3 }, { "name":"products", "label":"Products", "type":"array_of_objects", "required":true, "fields":[ {"name":"name","label":"Product Name","type":"text","required":true}, {"name":"size","label":"Size","type":"text","required":true}, {"name":"color","label":"Color","type":"text","required":true}, {"name":"quantity","label":"Quantity","type":"number","required":true,"min":1}, {"name":"price","label":"Price","type":"number","required":true,"min":0} ] } ]
Common regex patterns for validation (use in JSON with double backslashes):
"pattern": "^\\+?\\d{7,15}$""pattern": "^\\(\\d{3}\\)\\s?\\d{3}-\\d{4}$""pattern": "^\\d{5}(-\\d{4})?$""pattern": "^\\d{6}$""pattern": "^[a-zA-Z]+$""pattern": "^[a-zA-Z0-9]+$""pattern": "^[a-z0-9-]+$"\\d instead of \d, \\+ instead of \+)The array_of_objects type allows you to define arrays with nested field validation. Each item in the array is validated according to the nested fields configuration.
Configuration:
name: Field name (required)label: Field label (required)notification_label: Custom label for notifications (optional, priority: notification_label → label → name)type: Must be "array_of_objects" (required)required: Whether the array is required (default: false)fields: Array of field configurations for each object in the array (required)
Nested fields support all standard field types (text, email, tel, url, number, textarea, etc.) with full validation. Nested fields also support notification_label for custom labels in Telegram/email notifications.This plugin can connect to external services when explicitly enabled in a form's settings:
https://oauth2.googleapis.com/token, https://sheets.googleapis.com/v4/spreadsheets/...https://api.telegram.org/bot<token>/sendMessagemksddn_fh_before_submit — block submission before delivery channels runmksddn_fh_is_spam — custom spam rules when heuristics are enabledmksddn_fh_spam_multi_select_threshold — adjust multi-select spam thresholdmksddn_fh_render_turnstile(), mksddn_fh_enqueue_turnstile(), mksddn_fh_form_requires_turnstile()off | same_site | allowlist) in Advanced settingsorigin_not_allowed before file processing and delivery integrationssanitize_url (WordPress convention)mksddn_fh_trusted_origins_bypass for edge-case infrastructure bypasstrusted_origins_mode values are treated as off (logged, request allowed)off; explicit runtime defaults; no migration required for existing formsGoogleSheetsHandler::get_oauth_redirect_uri()TemplateParser::parse_for_email() for HTML-safe placeholder replacement in user reply emailsmksddn_fh_max_html_template_size for HTML template upload size limitget_page_url() method to extract page URL from refererarray_of_objects field type with full nested field validationarray_of_objects type only - prevents validation bypassvalidate_array_of_objects() method for comprehensive array validationsanitize_array_of_objects() method for type-based sanitizationfields propertytext type for arrays must be updated to array_of_objects typeoptions and multiple support in fields JSON/wp/v2/forms route; unified custom namespaceGET /wp-json/mksddn-forms-handler/v1/formsGET /wp-json/mksddn-forms-handler/v1/forms/{slug}uninstall.php to clean plugin options and transients (keeps CPT data)