Forms, spam filtering and marketing tracking
Contact and newsletter forms (Contact Form 7), the custom honeypot that guards them, the domain allow-list that stops legitimate enquiries being marked as spam, and the Force24 marketing tracking that fires behind cookie consent.
Why it exists
Section titled “Why it exists”Enquiry forms are the site’s lead capture, so a false spam positive costs a real enquiry. The theme therefore layers its own honeypot on top of CF7 and adds an ACF-managed allow-list of trusted email domains that overrides the spam verdict. Force24 is the School’s marketing automation platform and its tracking must not fire before consent.
Entry points
Section titled “Entry points”| Path | What it does |
|---|---|
wp-content/themes/supplychainschool/inc/cf7.php | Honeypot form tag, validation, auto-injection, nonce filter |
wp-content/themes/supplychainschool/inc/cf7.php:141 | add_honeypot() — injects three honeypot fields into every form |
wp-content/themes/supplychainschool/functions.php:695 | log_cf7_spam_submission() — the domain allow-list override |
wp-content/themes/supplychainschool/inc/components/fc-contact-form.php | Contact form block |
wp-content/themes/supplychainschool/inc/components/fc-newsletter-sign-up.php | Newsletter block |
wp-content/themes/supplychainschool/inc/force24-functions.php:2 | scss_generate_force24_tracking() on wp_head |
wp-content/themes/supplychainschool/assets/js/cookie-notification.js | Cookie notice |
wp-content/themes/supplychainschool/functions.php:172 | Enqueues js.cookie.js + cookie-notification.js |
How it works
Section titled “How it works”The honeypot
Section titled “The honeypot”inc/cf7.php is a vendored, modified copy of the Contact Form 7 Honeypot
plugin, running inside the theme:
wpcf7_add_form_tag(['honeypot'], …)registers a[honeypot name]tag withdo-not-storeandnot-for-mail(:44).- The tag handler (
:57) renders a<span>hidden with inlinedisplay:none !important; visibility:hidden !important, containing a label and a text input withtabindex="-1"andautocomplete="nope". The inline CSS can optionally be moved to an enqueued stylesheet via themove-inline-cssoption. - Validation (
:117) fails the submission if the field has any value or if the field is absent from$_POSTentirely (:132) — so a bot that strips the field is caught as well as one that fills it. add_honeypot()(:143) filterswpcf7_contact_form_propertiesand prepends three honeypots to every form that does not already contain the wordhoneypot:[honeypot your-firstname][honeypot your-mobilephone][honeypot your-companyname].
The field names are chosen to look attractive to autofill-style bots.
CF7’s own nonce verification is disabled: add_filter('wpcf7_verify_nonce', '__return_false') (:153). The honeypot is the replacement anti-bot
measure. This also means CF7 submissions work from cached pages, which is
likely the real reason.
The spam allow-list
Section titled “The spam allow-list”log_cf7_spam_submission() (functions.php:695) hooks wpcf7_spam:
- Only acts when something has already flagged the submission as spam.
error_log('Contact Form 7 marked a form submission as spam.').- Reads the ACF options repeater
whitelisted_domains(rows with adomainsubfield). - Finds the first value in the posted data that validates as an email.
- Compares that email’s domain, lowercased, for an exact match against each allowed domain.
- On a match, returns
false— not spam.
An earlier attempt at the same thing against Akismet specifically
(wpcf7_akismet_intercepted) is commented out immediately above
(functions.php:663-693). The live version hooks the generic wpcf7_spam
filter instead, which covers Akismet and the honeypot alike.
Force24 tracking
Section titled “Force24 tracking”scss_generate_force24_tracking() (inc/force24-functions.php:2) prints the
Force24 loader in wp_head, with a different tracking id and client id per
blog: blogs 1, 2, 6 and 7 each have their own pair. Blogs 3 and 5 get
nothing.
Only blog 1 is consent-gated. There, the snippet is wrapped in a 1200ms
setTimeout that checks window.cookiehub.hasConsented("preferences")
before loading (:10-24). Blogs 2, 6 and 7 load the tracker unconditionally.
Cookie consent itself is CookieHub (third-party, injected outside the theme)
plus the theme’s own cookie-notification.js built on js.cookie.js.
Google Tag Manager is in header.php, conditionally.
Configuration
Section titled “Configuration”- Contact Form 7 plugin — required;
inc/cf7.php:14deactivates itself and shows an admin notice if CF7 is missing. - ACF options field
whitelisted_domains(repeater with adomainsubfield) on an options page. - Force24 tracking id and client id are hard-coded per blog in
inc/force24-functions.php— not options, not constants. - Akismet is installed; Flamingo stores submissions.
- Filters available:
wpcf7_honeypot_accessibility_message,wpcf7_honeypot_container_css,wpcf7_honeypot_html_output.
Invariants and gotchas
Section titled “Invariants and gotchas”- CF7 nonce verification is globally off (
inc/cf7.php:153). Do not assume a nonce is present on any CF7 submission, and do not re-enable it without checking whether forms still work from cached pages. - The allow-list matches the first email-looking value in the submission
(
functions.php:707). On a form with two email fields (say, “your email” and “colleague’s email”) whichever iterates first wins, and field order in$_POSTis not guaranteed to match the form. - Domain matching is exact, not suffix-based. Allowing
example.comdoes not allowmail.example.comorexample.co.uk. - Every honeypot-caught spam submission writes to
error_log(functions.php:699) with no rate limiting. - Three honeypot fields are prepended to every CF7 form whose markup does not already contain the string “honeypot”. A form that mentions the word for any other reason silently gets none.
- The honeypot renders a visible-to-screen-readers label (“Please leave this
field empty”) inside a
display:nonecontainer — deliberate, for accessibility, and filterable. - Force24 loads unconsented on blogs 2, 6 and 7. Only blog 1 checks CookieHub. If a consent question comes up for the Australian, Carbon or US sites, this is the code to look at.
- The consent check is a fixed 1200ms
setTimeout, not an event listener. If CookieHub loads slower than that,window.cookiehubis undefined and tracking never fires at all — it fails closed, which is the safe direction but means missing data rather than an error. - Blog 6 (Carbon Calculator) has its own Force24 pair, so calculator page views are tracked as marketing activity.
Changing it safely
Section titled “Changing it safely”- New trusted domain: add a row to the
whitelisted_domainsACF options repeater. No code change. - New Force24 site: add an
elseif ($blog_id == N)branch ininc/force24-functions.phpwith that site’s ids, and copy the CookieHub consent wrapper from the blog 1 branch — the other branches are the pattern you do not want to follow. - Changing the honeypot field names means changing them in
add_honeypot()only; the validation is generic over the tag name. - If you replace the honeypot with anything else, re-check
wpcf7_verify_nonce— the theme currently relies on the honeypot as the only bot barrier. - Verify by hand: submit a form normally; submit with a honeypot field filled
(expect the spam message); submit from an allow-listed domain with Akismet
in test mode and confirm it lands in Flamingo as not-spam; check
error_logfor the spam line. - Deliberately not abstracted:
inc/cf7.phpis a vendored plugin copy. Keep the upstream structure recognisable so it can be diffed against the original.
None.
Related: [[acf-flexible-content-blocks]], [[site-chrome-and-navigation]], [[member-directory-and-stats]].