Skip to content

Latest commit

 

History

4 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

TContactForm

TContactForm is a standalone WordPress contact-form plugin. It does not depend on Contact Form 7 and does not alter WordPress core.

The source code, comments and default English copy use British English. English (UK) and Spanish (Mexico) are included as starter languages, while administrators can add, remove and configure their own form languages, locale codes and text directions.

Included features

  • Modern palette-and-canvas field builder with a full-screen new-form template chooser, 13 quick-start templates, search, drag reordering, duplication, language tabs and friendly choice editors for text, email, telephone, URL, number, calculations, textarea, select, radio, checkbox, date, time, file, hidden, consent, HTML, signature and repeater fields.
  • A launcher-inspired palette using button blue #5da2cf, bright cyan #3caae8, medium navy #245169, green #71a94c and yellow #ecc13f, with per-form colour controls.
  • Built-in custom maths/question challenges, Cloudflare Turnstile, hCaptcha, Google reCAPTCHA v2/v3 and Arkose Labs support with server-side verification and encrypted private keys.
  • Conditional field visibility.
  • Standard multi-step forms and one-question-at-a-time lead forms with progress, transitions and optional automatic advancement for single-choice answers.
  • Repeaters with visual child-field editing, minimum and maximum item limits, visitor-controlled rows and per-row calculations.
  • Safe live calculations without eval, including arithmetic, comparisons, approved functions, chained calculated fields and repeater aggregates.
  • Opt-in encrypted form-abandonment capture with optional same-tab recovery, delayed administrator alerts, secure visitor recovery-email links, private administration, retention controls and WordPress privacy export/erase support.
  • Client-side style import/export limited to visual settings, allowing lead-form styles to be reused without exposing form data or credentials.
  • Mouse, pen and touch signatures saved as encrypted PNG attachments.
  • Autocomplete from static values, published posts/custom post types, WordPress display names, or explicitly configured WordPress-prefixed database tables.
  • Encrypted database storage for submissions and private settings.
  • Attachment bytes stored inside the encrypted database entry by default, with an optional encrypted private-file backend, protected administrative downloads and configurable retention.
  • Email notifications with Reply-To selection, file attachments and queued, UTF-8 PDF attachments rendered by Dompdf.
  • HMAC-SHA256 webhooks with SSRF safeguards, no redirects, retry backoff and delivery status.
  • Entry browser, status management, permanent deletion and UTF-8 CSV export.
  • WordPress privacy exporter and eraser integration.
  • Shortcode and dynamic Gutenberg block.
  • Administrator-managed languages with locale matching, optional public language selector, LTR/RTL support and WPML language detection when WPML is active.
  • Extension hooks for PDF post-processing, field behaviour, MIME policies and downstream integrations.

Database support

The plugin only uses WordPress's $wpdb abstraction for queries. It works normally on MySQL and MariaDB.

For SQLite, WordPress must already be running with a compatible SQLite db.php drop-in, such as the WordPress SQLite Database Integration feature plugin. TContactForm does not replace the site's database driver.

Installation

Deployment ZIP

  1. Install the release ZIP in Plugins → Add New → Upload Plugin.
  2. Activate TContactForm.
  3. Open Forms → Add new form.
  4. Open Forms → Languages to configure the site's locales.
  5. Configure the form, publish it and insert [tcontactform id="123"], a locale-locked shortcode such as [tcontactform id="123" language="fr_FR"], or the TContactForm block.

Building from source

The source archive deliberately does not include Composer dependencies. From the plugin root, run:

./scripts/build-zip.sh

The build script installs the pinned PDF dependency with Composer, runs lightweight checks and creates a deployment ZIP containing vendor/. Composer 2, PHP and zip must be available on the build machine.

Activation creates a sample multilingual contact form with English (UK) and Spanish (Mexico) starter copy.

Language configuration

Open Forms → Languages to manage the languages available to every form. Up to 20 languages may be configured. Each language has:

  • a WordPress-style locale such as en_GB, es_MX, fr_FR, ar_SA or ru_RU;
  • an administrative name and a native public name;
  • left-to-right or right-to-left text direction;
  • editable public navigation, signature, security and validation messages.

The selected default is used when a visitor, shortcode, WPML locale or tcf_lang query parameter does not resolve to another configured language. A form may optionally show a public language selector. A shortcode can lock a form to one configured locale, for example:

[tcontactform id="123" language="ar_SA"]

Labels, help text, choices, email subjects and bodies, success messages and PDF templates gain an editor for every configured language. Existing translations are preserved when a language is temporarily removed from the active list.

Requirements

  • WordPress 6.5 or later.
  • PHP 8.1 or later with mbstring and DOM support.
  • Either libsodium, or OpenSSL with AES-256-GCM support.
  • Composer-installed dependencies for PDF attachments; the exact Dompdf version is pinned in composer.json.
  • JavaScript enabled for public submissions and the visual builder.
  • MySQL/MariaDB through standard WordPress, or an already configured compatible SQLite db.php integration.

Attachment storage

Database mode is the default. Attachment bytes are base64-packed inside the submission and protected by the submission’s authenticated-encryption envelope. This keeps entries and attachments together in MySQL/MariaDB or SQLite backups.

Private-file mode may be selected per form to reduce database growth. In that mode, uploaded files are encrypted before storage. By default they are stored below the WordPress uploads directory in tcontactform-private, with Apache and IIS denial files as defence in depth.

For the strongest deployment, define a directory outside the public web root in wp-config.php:

define( 'TCF_PRIVATE_UPLOAD_DIR', '/srv/private/tcontactform-files' );

The PHP process must be able to create and write to that directory.

Encryption key stability

Encryption keys are derived from the WordPress authentication keys and salts. Changing those values makes previously stored entries and files unreadable unless the old values are restored. Back up wp-config.php securely together with the database and private attachment directory.

A managed deployment may provide a stable 32-byte binary key through the tcf_encryption_key filter. The filter must return the same key for every request and backup restoration.

Webhook configuration

The Webhooks tab accepts a JSON array:

[
  {
    "id": "crm",
    "url": "https://crm.example.com/forms/intake",
    "secret": "replace-with-a-long-random-secret",
    "enabled": true,
    "headers": {
      "x-account": "website"
    }
  }
]

Each request includes:

  • X-TContactForm-Event
  • X-TContactForm-Timestamp
  • X-TContactForm-Signature: sha256=<HMAC>

The signed value is <timestamp>.<raw JSON body>.

Builder JSON examples

Options

[
  {
    "value": "sales",
    "label": {
      "en_GB": "Sales",
      "es_MX": "Ventas",
      "fr_FR": "Ventes"
    }
  }
]

Conditional logic

{
  "field": "department",
  "operator": "equals",
  "value": "sales"
}

Supported operators are equals, not_equals, contains, not_empty and empty.

Autocomplete

Static values:

{
  "enabled": true,
  "source": "static",
  "values": ["London", "Manchester", "Ciudad de México", "Monterrey"]
}

Posts or a custom post type:

{
  "enabled": true,
  "source": "posts",
  "post_type": "office"
}

User display-name autocomplete requires the visitor to have the list_users capability. Public exposure stays disabled unless trusted site code explicitly opts in through tcf_allow_public_user_autocomplete.

Database table source (use the site’s actual WordPress table prefix):

{
  "enabled": true,
  "source": "database",
  "table": "wp_offices",
  "value_column": "city",
  "search_column": "city",
  "public": false
}

Database autocomplete is deny-by-default even when the JSON marks it public. Trusted site code must return true from tcf_allow_autocomplete_table for each specifically approved table. Only simple WordPress-prefixed identifiers are accepted, sensitive-looking column names are rejected and results are rate-limited and length-bounded.

Repeater children

[
  {
    "id": "person_name",
    "type": "text",
    "label": {
      "en_GB": "Person's name",
      "es_MX": "Nombre de la persona",
      "fr_FR": "Nom de la personne"
    },
    "required": true,
    "width": "half"
  },
  {
    "id": "person_email",
    "type": "email",
    "label": {
      "en_GB": "Email address",
      "es_MX": "Correo electrónico",
      "fr_FR": "Adresse e-mail"
    },
    "required": true,
    "width": "half"
  }
]

Bot protection

Open a form and choose Delivery, styling and security → Bot protection. Select one provider and enter its public and private credentials. Supported providers are Cloudflare Turnstile, hCaptcha, Google reCAPTCHA v2 checkbox, Google reCAPTCHA v3 score and Arkose Labs.

Provider scripts are loaded only on pages that render a protected form. Public configuration contains the site/public key but never the secret/private key. The REST submission endpoint verifies every token with the provider after the plugin's local token, honeypot, timing and rate-limit checks. Missing credentials, transport failures, invalid hostnames, mismatched actions, low reCAPTCHA v3 scores and replayed or timed-out Arkose sessions fail closed.

Arkose installations must enter the company endpoint prefix supplied by Arkose, for example yourcompany, rather than a complete hostname. See docs/CAPTCHA.md.

PDF behaviour

PDF attachments use the Composer-pinned Dompdf engine and its UTF-8-capable bundled default font. The engine is loaded only when a queued PDF notification runs; ordinary page views and submissions do not load Dompdf. PDF notifications are scheduled through WordPress Cron, retried up to three times and protected by a per-submission lock. On low-traffic sites, configure a real system cron to call WordPress Cron reliably.

The renderer treats the administrator template and all submitted values as text. It escapes them before producing a small internal HTML document. Remote resources, PHP execution and JavaScript are disabled; the renderer is chrooted to the plugin and its private working directory; output is rejected unless it starts with a PDF signature and stays within the size ceiling. Temporary email attachments use random names, mode 0600 and are removed in a finally block.

The tcf_pdf_bytes filter may post-process the generated bytes. The result is accepted only when it remains a PDF and stays below the output limit:

add_filter(
    'tcf_pdf_bytes',
    function ( string $pdf, int $submission_id, WP_Post $form, array $payload, array $settings ): string {
        return $pdf;
    },
    10,
    5
);

Security model

  • All public input is validated against the saved form schema and sanitised by field type.
  • All output is escaped at the rendering boundary.
  • Administrative actions use capabilities and nonces.
  • Public forms use expiring signed form tokens, a honeypot, minimum completion time, request-size limits and per-client rate limiting. Optional CAPTCHA/challenge tokens are then verified server-side with the selected provider.
  • Database operations use $wpdb prepared queries or typed insert/update methods.
  • Submission bodies, metadata, webhook secrets and private files use authenticated encryption.
  • Raw IP addresses are not stored. A keyed, non-reversible client hash is used for rate limiting.
  • Uploads have per-file and aggregate limits, dangerous-name rejection, WordPress type checks and content-based validation for the built-in image, PDF, DOC, DOCX, text and CSV types. SVG is not accepted by default.
  • Webhooks require HTTPS by default, reject credentials, fragments, unsafe ports, unresolved hosts and private/reserved A or AAAA records, and retain wp_safe_remote_post(), TLS verification, zero redirects and a bounded response body at delivery time.
  • File downloads require an authenticated capability check and a single-use WordPress nonce URL.
  • Uninstall retains data unless TCF_DELETE_DATA_ON_UNINSTALL is explicitly set to true.

See docs/SECURITY.md for deployment guidance.

Important scope notes

This is a substantial working foundation, not a byte-for-byte clone of Contact Form 7 or every commercial add-on. In particular:

  • It does not import existing Contact Form 7 forms or entries.
  • Google Maps address suggestions are not bundled because they require external credentials, billing and privacy consent. The autocomplete layer is designed to be extended with another provider.
  • The included PDF customiser is template-based rather than a drag-and-drop page designer.
  • The signature field captures a drawn mark; it is not identity verification, certificate-based signing or a complete legal e-signature workflow.
  • Payment gateways, marketing platforms and CRM-specific adapters are not bundled; webhooks and WordPress hooks provide the integration boundary. CAPTCHA support is built in for Turnstile, hCaptcha, reCAPTCHA v2/v3 and Arkose Labs.
  • Front-end submission, repeaters, signatures, autocomplete and multi-step navigation require JavaScript.
  • A production release should be tested on the exact WordPress, PHP, database drop-in, web server, mail system and object-cache stack used by the site.

Development checks

Run:

./scripts/check.sh

The script checks PHP syntax, JavaScript syntax and searches for common unsafe patterns. It does not replace WordPress Plugin Check, PHP_CodeSniffer, integration tests, penetration testing or a professional code review.

Licence

GPL-2.0-or-later.

0.4.0 form-growth feature pack

  • Fixed the new-form workflow so a full template gallery opens automatically on Forms → Add New; Browse templates is also permanently visible in the empty canvas and builder toolbar.
  • Expanded the starter pack to 13 templates, including conversational leads, team registration, repeatable product orders, BMI and loan calculators.
  • Added visual repeater child-field editing, visitor add/remove controls, minimum/maximum rows, row calculations and aggregate calculations.
  • Added lead-form presentation that converts existing forms to one-question-at-a-time without rebuilding, with progress, slide/fade transitions and optional choice auto-advance.
  • Added a deterministic server/client calculation engine with no eval, bounded expressions, approved functions and authoritative server-side recalculation.
  • Added custom maths or multilingual question CAPTCHA alongside Turnstile, hCaptcha, reCAPTCHA and Arkose.
  • Added encrypted partial-entry capture, optional tab-scoped browser recovery, delayed administrator notifications, optional visitor recovery emails with same-origin fragment-bearer links, retention, private review/delete screens and privacy exporter/eraser integration. Uploads and signatures are never autosaved.
  • Added safe style import/export for colours, width and radius only.

0.3.0 security and interface update

  • Replaced the legacy Windows-1252 PDF writer with a Composer-pinned Dompdf renderer that preserves UTF-8 text.
  • Moved PDF generation and its email delivery out of the public request and into a locked, retryable WordPress Cron job.
  • Added content-aware upload verification, aggregate limits and dangerous double-extension rejection.
  • Made database and public user autocomplete deny-by-default, rate-limited and bounded.
  • Tightened webhook destination, header, payload and response validation while retaining WordPress's safe HTTP transport.
  • Rebuilt the form builder as a modern palette-and-canvas interface while retaining the green #64c832, yellow #f6cd42 and blue #1595b8 palette.

0.2.2 compatibility fix

The public-request security methods use bool|WP_Error return types. This keeps the plugin compatible with its declared minimum of PHP 8.1; the standalone literal true type is only available from PHP 8.2.

0.2.3 visual adjustment

The preset action yellow is now slightly lighter (#f6cd42). Coloured front-end and administrator buttons use white text with a subtle text shadow for legibility.

0.3.2 CAPTCHA, templates and palette refinement

  • Matched the builder identity mark and menu controls to the reference button blue and replaced the near-black frame with medium launcher blues.
  • Added Cloudflare Turnstile, hCaptcha, Google reCAPTCHA v2/v3 and Arkose Labs with lazy client scripts, encrypted secrets and server-side verification.
  • Added eight premade templates for contact, quote, support, appointments, events, feedback, recruitment and newsletters.
  • Added provider-specific settings, multilingual public status messages and security checks for hostname, action, score, replay and timeout responses.

0.3.1 launcher-inspired visual update

  • Added a dark navy application frame, cyan navigation strips, yellow primary actions, orange edge details and a green status bar to the form builder.
  • Added field-type symbols, a compact builder identity block and a clearer canvas header.
  • Applied the same visual language to public forms with square controls, angled action buttons and responsive behaviour.
  • Updated the default and one-click colour preset. Exact unmodified 0.3.0 defaults migrate automatically; customised form colours are preserved.

About

Free Premium Contact Form Plugin

Resources

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages