{"id":191192,"date":"2024-05-10T15:00:08","date_gmt":"2024-05-10T15:00:08","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/cf7-to-hubspot\/"},"modified":"2026-10-20T10:03:46","modified_gmt":"2026-10-20T10:03:46","slug":"connect-cf7-to-hubspot","status":"publish","type":"plugin","link":"https:\/\/ast.wordpress.org\/plugins\/connect-cf7-to-hubspot\/","author":17872683,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.4.2","stable_tag":"1.4.2","tested":"7.1.3","requires":"5.9","requires_php":"8.0","requires_plugins":null,"header_name":"Connect CF7 to HubSpot","header_author":"ProCoders","header_description":"Connect CF7 to HubSpot plugin allows you to send Contact Form 7 data to HubSpot.","assets_banners_color":"ffffff","last_updated":"2026-10-20 10:03:46","external_support_url":"","external_repository_url":"","donate_link":"https:\/\/procoders.tech\/","header_plugin_uri":"http:\/\/procoders.tech\/solutions\/platforms\/wordpress\/plugin-development\/cf7-hs-integration\/","header_author_uri":"https:\/\/procoders.tech\/","rating":5,"author_block_rating":0,"active_installs":300,"downloads":7166,"num_ratings":3,"support_threads":1,"support_threads_resolved":1,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"0.1.1.2":{"tag":".1.1.2","author":"procoders","date":"2024-05-13 08:12:44","revision":3085497},"0.1.1.4":{"tag":".1.1.4","author":"procoders","date":"2024-06-05 12:27:34","revision":3098003},"0.1.1.6":{"tag":".1.1.6","author":"procoders","date":"2024-09-25 11:52:44","revision":3157508},"1.0":{"tag":"1.0","author":"procoders","date":"2024-05-10 14:59:50","revision":3084596},"1.1":{"tag":"1.1","author":"procoders","date":"2024-05-10 15:04:15","revision":3084603},"1.1.1":{"tag":"1.1.1","author":"procoders","date":"2024-05-13 06:55:47","revision":3085444},"1.1.3":{"tag":"1.1.3","author":"procoders","date":"2024-05-13 13:30:42","revision":3085871},"1.1.4":{"tag":"1.1.4","author":"procoders","date":"2024-06-06 18:10:41","revision":3098873},"1.1.5":{"tag":"1.1.5","author":"procoders","date":"2024-06-10 12:37:13","revision":3100553},"1.1.7":{"tag":"1.1.7","author":"procoders","date":"2024-11-20 09:23:57","revision":3192939},"1.1.8":{"tag":"1.1.8","author":"procoders","date":"2024-11-20 14:53:49","revision":3193278},"1.1.9":{"tag":"1.1.9","author":"procoders","date":"2025-02-18 15:04:22","revision":3242729},"1.2.0":{"tag":"1.2.0","author":"procoders","date":"2025-04-16 13:44:50","revision":3274805},"1.2.1":{"tag":"1.2.1","author":"procoders","date":"2025-07-28 09:04:42","revision":3335218},"1.3":{"tag":"1.3","author":"procoders","date":"2026-03-02 09:23:43","revision":3472522},"1.3.1":{"tag":"1.3.1","author":"procoders","date":"2026-04-08 11:03:00","revision":3501564},"1.3.2":{"tag":"1.3.2","author":"procoders","date":"2026-04-15 08:24:58","revision":3506789},"1.3.2.1":{"tag":"1.3.2.1","author":"procoders","date":"2026-05-27 15:27:13","revision":3550881},"1.3.3":{"tag":"1.3.3","author":"procoders","date":"2026-05-28 09:05:54","revision":3551784},"1.3.4":{"tag":"1.3.4","author":"procoders","date":"2026-06-24 18:14:45","revision":3585237},"1.3.5":{"tag":"1.3.5","author":"procoders","date":"2026-08-18 08:15:26","revision":3652259},"1.3.6":{"tag":"1.3.6","author":"procoders","date":"2026-08-21 18:31:19","revision":3659494},"1.3.7":{"tag":"1.3.7","author":"procoders","date":"2026-08-21 18:35:50","revision":3659499},"1.3.8":{"tag":"1.3.8","author":"procoders","date":"2026-08-21 19:04:09","revision":3659533},"1.4.0":{"tag":"1.4.0","author":"procoders","date":"2026-10-14 12:59:35","revision":3746409},"1.4.1":{"tag":"1.4.1","author":"procoders","date":"2026-10-19 14:43:49","revision":3755004},"1.4.2":{"tag":"1.4.2","author":"procoders","date":"2026-10-20 10:03:46","revision":3756392}},"upgrade_notice":{"1.4.2":"<p>Readme update only; nothing changes on your site.<\/p>","1.4.1":"<p>Fixes records that HubSpot rejected when a field was mapped to &quot;Attachments&quot;. Adds developer hooks for changing the properties sent to each HubSpot object and for reacting to the result; nothing changes unless your own code uses them.<\/p>","1.4.0":"<p>Several HubSpot objects per form, a masked database log with a new Logs screen, throttled error emails, and redesigned admin screens. Requires WordPress 5.9+. Existing mappings keep working; the old debug.log stays readable on the Logs screen until it expires.<\/p>"},"ratings":{"1":0,"2":0,"3":0,"4":0,"5":3},"assets_icons":{"icon-128x128.jpg":{"filename":"icon-128x128.jpg","revision":3084596,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-128x128.png":{"filename":"icon-128x128.png","revision":3084596,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.jpg":{"filename":"icon-256x256.jpg","revision":3084596,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3084596,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256},"icon.svg":{"filename":"icon.svg","revision":3084596,"resolution":false,"location":"assets","locale":false}},"assets_banners":{"banner-1544x500.jpg":{"filename":"banner-1544x500.jpg","revision":3084603,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":501},"banner-772x250.jpg":{"filename":"banner-772x250.jpg","revision":3084603,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["0.1.1.2","0.1.1.4","0.1.1.6","1.0","1.1","1.1.1","1.1.3","1.1.4","1.1.5","1.1.7","1.1.8","1.1.9","1.2.0","1.2.1","1.3","1.3.1","1.3.2","1.3.2.1","1.3.3","1.3.4","1.3.5","1.3.6","1.3.7","1.3.8","1.4.0","1.4.1","1.4.2"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3746409,"resolution":"1","location":"assets","locale":"","width":1280,"height":1582},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3746409,"resolution":"2","location":"assets","locale":"","width":1280,"height":820},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3746409,"resolution":"3","location":"assets","locale":"","width":1280,"height":1341},"screenshot-4.png":{"filename":"screenshot-4.png","revision":3746409,"resolution":"4","location":"assets","locale":"","width":1280,"height":820}},"screenshots":{"1":"The mapping screen of a form: one card per HubSpot object (\"#1 Contact\", \"#2 Deal\"), each with its own field mapping, the association with the object above it, and the Sync switch with Save Changes at the top.","2":"The forms list: every Contact Form 7 form with its sync status (Active, Paused, Not set up), the HubSpot objects it sends to, status tabs, search, and a button to set up or edit its mapping.","3":"The Settings screen: connect HubSpot with an access token, choose background processing, attribution and journey events, and where error emails go.","4":"The Logs screen: failed, blocked and retried submissions with search, result tabs and a form filter; an entry opens under its row with the masked request and the properties HubSpot rejected."}},"plugin_section":[],"plugin_tags":[1152,1150,8904,597,335],"plugin_category":[58],"plugin_contributors":[219245],"plugin_business_model":[],"class_list":["post-191192","plugin","type-plugin","status-publish","hentry","plugin_tags-contact-form-7","plugin_tags-crm","plugin_tags-hubspot","plugin_tags-integration","plugin_tags-leads","plugin_category-user-management","plugin_contributors-procoders","plugin_committers-procoders","plugin_support_reps-org100h"],"banners":{"banner":"https:\/\/ps.w.org\/connect-cf7-to-hubspot\/assets\/banner-772x250.jpg?rev=3084603","banner_2x":"https:\/\/ps.w.org\/connect-cf7-to-hubspot\/assets\/banner-1544x500.jpg?rev=3084603","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":"https:\/\/ps.w.org\/connect-cf7-to-hubspot\/assets\/icon.svg?rev=3084596","icon":"https:\/\/ps.w.org\/connect-cf7-to-hubspot\/assets\/icon.svg?rev=3084596","icon_2x":false,"generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/connect-cf7-to-hubspot\/assets\/screenshot-1.png?rev=3746409","caption":"The mapping screen of a form: one card per HubSpot object (\"#1 Contact\", \"#2 Deal\"), each with its own field mapping, the association with the object above it, and the Sync switch with Save Changes at the top."},{"src":"https:\/\/ps.w.org\/connect-cf7-to-hubspot\/assets\/screenshot-2.png?rev=3746409","caption":"The forms list: every Contact Form 7 form with its sync status (Active, Paused, Not set up), the HubSpot objects it sends to, status tabs, search, and a button to set up or edit its mapping."},{"src":"https:\/\/ps.w.org\/connect-cf7-to-hubspot\/assets\/screenshot-3.png?rev=3746409","caption":"The Settings screen: connect HubSpot with an access token, choose background processing, attribution and journey events, and where error emails go."},{"src":"https:\/\/ps.w.org\/connect-cf7-to-hubspot\/assets\/screenshot-4.png?rev=3746409","caption":"The Logs screen: failed, blocked and retried submissions with search, result tabs and a form filter; an entry opens under its row with the masked request and the properties HubSpot rejected."}],"raw_content":"<!--section=description-->\n<p>Sends each Contact Form 7 submission to HubSpot. Your forms stay as they are.<\/p>\n\n<p>One form can create several linked records. A quote request, for example, can create a contact, their company and a deal in the pipeline and stage you choose. A support form can open a ticket. You can also send a form to an existing HubSpot form, so HubSpot workflows and page tracking treat it like a HubSpot form.<\/p>\n\n<h4>Setup<\/h4>\n\n<ol>\n<li>Create a HubSpot service key with the scopes from the FAQ and paste it into <strong>CF7 to HubSpot \u2192 Settings<\/strong>.<\/li>\n<li>Open <strong>CF7 to HubSpot \u2192 Forms<\/strong> and pick a form.<\/li>\n<li>Add the HubSpot objects, map the fields, turn Sync on.<\/li>\n<\/ol>\n\n<h4>Features<\/h4>\n\n<ul>\n<li>Contact, Company, Deal and Ticket from one form, each with its own mapping, associated with each other.<\/li>\n<li>HubSpot form target, with the HubSpot tracking cookie and the page URL.<\/li>\n<li>Update the contact with the same email, or always create a new one.<\/li>\n<li>Deal pipeline and stage.<\/li>\n<li>Uploaded files attached to the records.<\/li>\n<li>Custom HubSpot properties.<\/li>\n<li>Consent check: a submission from an unsubscribed email is not sent.<\/li>\n<li>Logs with what HubSpot answered and which properties it rejected. Personal data is masked.<\/li>\n<li>Error emails. Repeats of the same error within an hour come as one summary.<\/li>\n<li>Optional background sending: the visitor does not wait for HubSpot, failed jobs are retried up to three times. Uses Action Scheduler when available, WordPress cron otherwise.<\/li>\n<li>UTM parameters and click ids (gclid, fbclid) to the properties you map them to.<\/li>\n<li>Optional HubSpot custom events: form submitted, synced, failed.<\/li>\n<li>Developer hooks, see the FAQ.<\/li>\n<\/ul>\n\n<h3>External services<\/h3>\n\n<p>This plugin sends Contact Form 7 submissions to HubSpot, a third-party service, when a form is submitted and synced. It sends the values of the mapped form fields, uploaded files that are mapped, and, when enabled, attribution values; for HubSpot form targets it also sends the visitor's IP address, the HubSpot tracking cookie and the page the form was sent from. In the admin it reads your HubSpot properties, forms, pipelines and subscription types to fill the mapping screens.<\/p>\n\n<p>The plugin sends requests to:<\/p>\n\n<ul>\n<li>https:\/\/api.hubapi.com<\/li>\n<li>https:\/\/api.hsforms.com<\/li>\n<\/ul>\n\n<p>HubSpot Terms of Service: https:\/\/legal.hubspot.com\/terms-of-service\nHubSpot Privacy Policy: https:\/\/legal.hubspot.com\/privacy-policy<\/p>\n\n<h3>Privacy<\/h3>\n\n<p>Attribution cookies are off by default. When you turn on \"Attribution cookies\" in the plugin settings, the site stores the campaign parameters (utm_source, utm_medium, utm_campaign, utm_term, utm_content) and ad click ids (gclid, fbclid) of the visitor's landing page in first-party cookies named cf7hs_* for up to 30 days (some browsers shorten this). When a consent plugin supports the WP Consent API, the cookies are set only after marketing consent. The values are sent to HubSpot with a contact form the visitor submits. Marketing cookies may need visitor consent where the law requires it.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Install and activate <a href=\"https:\/\/wordpress.org\/plugins\/contact-form-7\/\">Contact Form 7<\/a> if your site does not have it yet.<\/li>\n<li>In WordPress go to <strong>Plugins \u2192 Add New Plugin<\/strong>, search for \"Connect CF7 to HubSpot\", then click <strong>Install Now<\/strong> and <strong>Activate<\/strong>.<\/li>\n<li>Go to <strong>CF7 to HubSpot \u2192 Settings<\/strong>, paste your HubSpot service key (see the FAQ for how to create one) and click <strong>Connect<\/strong>.<\/li>\n<li>Go to <strong>CF7 to HubSpot \u2192 Forms<\/strong>, open a form, add the HubSpot objects it should create, map the fields and turn Sync on.<\/li>\n<\/ol>\n\n<p><strong>WordPress Multisite:<\/strong> do not network-activate. Activate the plugin on each site that needs it; each site connects its own HubSpot account.<\/p>\n\n<!--section=faq-->\n<dl>\n<dt id=\"how%20do%20i%20get%20a%20hubspot%20access%20token%20%28service%20key%29%3F\"><h3>How do I get a HubSpot access token (service key)?<\/h3><\/dt>\n<dd><p>HubSpot no longer lets you create new private apps (since 28 September 2026 for new accounts, and 26 October 2026 for existing ones). Use a service key instead; a token from an existing private app keeps working.<\/p>\n\n<ul>\n<li>Log in to HubSpot as a super admin and create a service key: https:\/\/developers.hubspot.com\/docs\/apps\/developer-platform\/build-apps\/authentication\/account-service-keys<\/li>\n<li>Give it these scopes: crm.objects.contacts.read and .write, crm.objects.companies.read and .write, crm.objects.deals.read and .write, crm.objects.tickets.read and .write, crm.schemas.contacts.read, crm.schemas.companies.read, crm.schemas.deals.read, forms, files.write and communication_preferences.read. (A private app token with the older <code>tickets<\/code> and <code>files<\/code> scopes keeps working.)<\/li>\n<li>If you use journey (custom behavioral) events (cf7_form_submitted, cf7_form_synced, cf7_form_sync_failed), also add <strong>analytics.behavioral_events.send<\/strong> and <strong>behavioral_events.event_definitions.read_write<\/strong>, create matching custom event definitions in HubSpot, and enable Journey events in the plugin settings.<\/li>\n<li>Paste the key into CF7 to HubSpot \u2192 Settings \u2192 Access token and click Connect. The token is saved only after HubSpot accepts it.<\/li>\n<\/ul><\/dd>\n<dt id=\"does%20it%20work%20with%20the%20free%20hubspot%20crm%3F\"><h3>Does it work with the free HubSpot CRM?<\/h3><\/dt>\n<dd><p>Contacts, companies, deals, tickets and HubSpot forms use HubSpot's standard CRM and Forms APIs. Journey events use HubSpot custom events, which are not part of every HubSpot plan; leave them off if your plan does not have them.<\/p><\/dd>\n<dt id=\"can%20i%20send%20one%20form%20to%20several%20hubspot%20objects%3F\"><h3>Can I send one form to several HubSpot objects?<\/h3><\/dt>\n<dd><p>Yes. On the form's mapping screen click \"Add an object\" and pick a Company, Deal or Ticket (or another Contact). Each object has its own field mapping and can be associated with an object above it.<\/p><\/dd>\n<dt id=\"will%20it%20create%20duplicate%20contacts%3F\"><h3>Will it create duplicate contacts?<\/h3><\/dt>\n<dd><p>A Contact object has a switch: update the contact with the same email, or always create a new one.<\/p><\/dd>\n<dt id=\"can%20i%20put%20deals%20into%20a%20specific%20hubspot%20pipeline%3F\"><h3>Can I put deals into a specific HubSpot pipeline?<\/h3><\/dt>\n<dd><p>Yes. Add a Deal object to the form's mapping and choose its pipeline and deal stage.<\/p><\/dd>\n<dt id=\"can%20i%20send%20utm%20parameters%20and%20hidden%20fields%3F\"><h3>Can I send UTM parameters and hidden fields?<\/h3><\/dt>\n<dd><p>Yes. Any Contact Form 7 field, hidden fields included, can be mapped to a HubSpot property. UTM parameters and ad click ids are added only to the properties you map them to; turn on \"Attribution cookies\" to keep them from the landing page until the form is sent.<\/p><\/dd>\n<dt id=\"should%20i%20send%20to%20hubspot%20objects%20or%20to%20a%20hubspot%20form%3F\"><h3>Should I send to HubSpot objects or to a HubSpot form?<\/h3><\/dt>\n<dd><p>Send to a HubSpot form when you want HubSpot's form features: form-based workflows, form submission reports and the visitor's page history on the contact. Send to objects when you need companies, deals or tickets, or several linked records from one submission.<\/p><\/dd>\n<dt id=\"where%20do%20i%20see%20why%20a%20submission%20did%20not%20reach%20hubspot%3F\"><h3>Where do I see why a submission did not reach HubSpot?<\/h3><\/dt>\n<dd><p>Open CF7 to HubSpot \u2192 Logs. Click an entry to see what HubSpot answered and which properties it rejected. Personal data is masked; use \"Copy details\" to share the entry with support.<\/p><\/dd>\n<dt id=\"hubspot%20shows%20each%20submission%20twice\"><h3>HubSpot shows each submission twice<\/h3><\/dt>\n<dd><p>HubSpot's own tracking code can also collect Contact Form 7 submissions. In HubSpot, turn off \"Collect data from website forms\" under the non-HubSpot forms settings.<\/p><\/dd>\n<dt id=\"do%20visitors%20wait%20for%20hubspot%20when%20they%20submit%20a%20form%3F\"><h3>Do visitors wait for HubSpot when they submit a form?<\/h3><\/dt>\n<dd><p>Only if background processing is off. Turn it on in Settings and the form answers at once while the HubSpot requests run in the background.<\/p><\/dd>\n<dt id=\"how%20do%20i%20get%20help%20or%20suggest%20a%20feature%3F\"><h3>How do I get help or suggest a feature?<\/h3><\/dt>\n<dd><p>Post in the support forum of this plugin, or write to hello@procoders.tech.<\/p><\/dd>\n<dt id=\"how%20do%20i%20change%20what%20the%20plugin%20sends%20to%20hubspot%20from%20my%20own%20code%3F%20%28developer%20hooks%29\"><h3>How do I change what the plugin sends to HubSpot from my own code? (developer hooks)<\/h3><\/dt>\n<dd><p>Since 1.4.1 the plugin has developer hooks. They are for people who write PHP; there is no setting for them in the admin.<\/p>\n\n<ul>\n<li><code>cf7hs_object_payload<\/code> (filter, <code>$data, $module, $form_id, $context<\/code>): change the HubSpot properties of one object just before it is written. <code>$module<\/code> is <code>contacts<\/code>, <code>company<\/code>, <code>deals<\/code> or <code>tickets<\/code>, or the HubSpot form GUID when the form is sent to a HubSpot form. Register with 4 accepted arguments to receive <code>$context<\/code> (<code>index<\/code>, <code>action<\/code>, <code>post_id<\/code>, <code>request<\/code>, <code>async<\/code>, <code>attempt<\/code>).<\/li>\n<li><code>cf7hs_object_synced<\/code> (action, <code>$record_id, $module, $form_id, $outcome, $context<\/code>): an object was created or updated. Register with 5 accepted arguments to receive <code>$context<\/code>. <code>$record_id<\/code> is an integer, and 0 for a HubSpot form target.<\/li>\n<li><code>cf7hs_object_sync_failed<\/code> (action, <code>$module, $form_id, $outcome, $context<\/code>): an object failed or was skipped. Register with 4 accepted arguments to receive <code>$context<\/code>.<\/li>\n<li><code>cf7hs_submission_completed<\/code> (action, <code>$status, $form_id, $outcomes, $context<\/code>): the submission reached its final outcome. <code>$status<\/code> is <code>synced<\/code> when the first object was written, otherwise <code>failed<\/code>. Register with 4 accepted arguments to receive <code>$context<\/code>. It does not fire when consent blocks the submission.<\/li>\n<li><code>cf7hs_is_form( $form_id, $id_or_hash )<\/code>: true when the form is the one with that post id or that shortcode hash (the 7 or more characters in <code>[contact-form-7 id=\"2f24e69\"]<\/code>).<\/li>\n<\/ul>\n\n<p>Example: set the lifecycle stage to customer for contacts from one form only.<\/p>\n\n<pre><code>add_filter( 'cf7hs_object_payload', 'my_cf7hs_customer_stage', 10, 4 );\nfunction my_cf7hs_customer_stage( $data, $module, $form_id, $context ) {\n    if ( 'contacts' === $module &amp;&amp; cf7hs_is_form( $form_id, '2f24e69' ) ) {\n        $data['lifecyclestage'] = 'customer';\n    }\n    return $data;\n}\n<\/code><\/pre>\n\n<p>The value is written in the same request that creates or updates the contact, so it costs no extra API call. For a form sent to a HubSpot form, <code>$module<\/code> is the HubSpot form GUID, so test that instead of <code>'contacts'<\/code>: <code>if ( 'your-hubspot-form-guid' === $module &amp;&amp; cf7hs_is_form( $form_id, '2f24e69' ) )<\/code>.<\/p>\n\n<p>Lifecycle stage notes: use the internal value (<code>customer<\/code>, not \"Customer\"). Custom stages have numeric ids; read the options of the <code>lifecyclestage<\/code> property in HubSpot to find them. HubSpot only moves a lifecycle stage forward through the API and forms, so a contact who is already past <code>customer<\/code> stays where they are.<\/p>\n\n<p>Things to know:<\/p>\n\n<ul>\n<li>Keep callbacks idempotent. With asynchronous submissions the same object can reach your callback again on a retry (see <code>$context['attempt']<\/code>); <code>cf7hs_object_sync_failed<\/code> can repeat, <code>cf7hs_object_synced<\/code> effectively fires once per object. With async, uploaded files are attached after the objects are written, so <code>cf7hs_object_synced<\/code> can run before the files are attached.<\/li>\n<li><code>cf7hs_submission_completed<\/code> says <code>failed<\/code> when the first object was not written. Later objects may still have been written, and no retry follows then. <code>$outcomes<\/code> lists every object and is empty when the final attempt threw an error. A form whose first object has no mapped fields fires no hooks.<\/li>\n<li>Return values of the filter: <code>true<\/code>\/<code>false<\/code> are sent as <code>true<\/code>\/<code>false<\/code>, other scalars as text, and <code>''<\/code> clears the property in HubSpot. Arrays and other non-scalar values are dropped with a warning in the log. Date and datetime values are sent as epoch milliseconds in a string (for example <code>1760832000000<\/code>), which is what HubSpot expects, so a callback that sets a date property should send the same format. A multi-checkbox is one value joined with <code>;<\/code>. File fields and the HubSpot tracking context are not passed to the filter and cannot be changed by it.<\/li>\n<li>If a callback throws an error it is caught and logged as a warning, and the submission goes on. For the filter, the unfiltered properties are then sent, so changes made by earlier callbacks are discarded too.<\/li>\n<li>Warning about consent: the plugin checks consent before the filter runs. If your callback changes <code>email<\/code> or a consent property, the new value is sent without that check.<\/li>\n<li>Arguments of these hooks are only ever added at the end; new keys may appear in <code>$context<\/code>. <code>cf7hs_is_form<\/code> with a digit-only string of 7 or more characters matches the post id first, so it can differ from how Contact Form 7 resolves the same value.<\/li>\n<\/ul><\/dd>\n<dt id=\"other%20filters\"><h3>Other filters<\/h3><\/dt>\n<dd><p>cf7hs_log_ttl_days sets how many days log entries are kept (30 by default). <code>cf7hs_error_email_throttle_seconds<\/code> sets the window in which repeated error emails are counted instead of sent (one hour by default).<\/p><\/dd>\n<dt id=\"where%20is%20the%20source%20of%20the%20compiled%20admin%20css%3F\"><h3>Where is the source of the compiled admin CSS?<\/h3><\/dt>\n<dd><p>The admin stylesheets in src\/Admin\/Assets\/build\/ are compiled from the SCSS in src\/Admin\/Assets\/scss\/, which ships with the plugin. They are built with Dart Sass 1.105.1 and @wordpress\/base-styles 13.3.0:\n    sass --no-source-map --style=compressed --load-path=node_modules src\/Admin\/Assets\/scss:src\/Admin\/Assets\/build<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.4.2<\/h4>\n\n<ul>\n<li>Readme rewritten: shorter description, setup steps, installation from the Plugins screen, and new FAQ answers (free HubSpot CRM, duplicate contacts, UTM and hidden fields, HubSpot form or objects). The plugin code is unchanged.<\/li>\n<li>Changelog entries before 1.4.0 moved to changelog.txt.<\/li>\n<\/ul>\n\n<h4>1.4.1<\/h4>\n\n<ul>\n<li>Developer hooks: <code>cf7hs_object_payload<\/code> filters the HubSpot properties of each object before it is written (contacts, companies, deals, tickets and HubSpot forms), <code>cf7hs_object_synced<\/code> and <code>cf7hs_object_sync_failed<\/code> fire after each object, and <code>cf7hs_submission_completed<\/code> fires once per submission with its final outcome. They behave the same with and without asynchronous submissions.<\/li>\n<li><code>cf7hs_is_form( $form_id, $id_or_hash )<\/code> matches a form by post id or by the hash in its shortcode.<\/li>\n<li>A callback that throws an error is logged as a warning instead of breaking the submission or causing an asynchronous retry.<\/li>\n<li>Settings and the FAQ list the exact scopes a HubSpot service key needs: read and write for contacts, companies, deals and tickets, schema reads for contacts, companies and deals, forms, files.write and communication_preferences.read. A private app token with the older scopes keeps working.<\/li>\n<li>A deal's pipeline and stage are never sent with any other HubSpot object, even if a form's settings were saved outside the mapping screen.<\/li>\n<li>Fixed: a field mapped to \"Attachments\" was also sent to HubSpot as a property named <code>attachment_field<\/code>. On a portal without such a property HubSpot rejected the whole record, so the contact (or deal, company, ticket) was not created. The upload is now only attached to the record.<\/li>\n<\/ul>\n\n<h4>1.4.0<\/h4>\n\n<ul>\n<li>Send one form to several HubSpot objects: Contact, Company, Deal and Ticket, each with its own mapping and an association with an object above it. A HubSpot form target stays a single object.<\/li>\n<li>Contacts: one switch chooses between updating the contact whose email already exists and always creating a new one.<\/li>\n<li>Uploaded files are attached only to the objects whose mapping includes them, in sync and async mode.<\/li>\n<li>Consent is checked on the CRM path too: a CRM form can choose the subscription types it enforces, and a submission is blocked when the email is unsubscribed or HubSpot cannot be asked.<\/li>\n<li>Opt-in first-touch attribution cookies that wait for marketing consent through the WP Consent API.<\/li>\n<li>The access token is saved only after HubSpot accepts it.<\/li>\n<li>Logs move from debug.log to a database table with personal data masked, kept for 30 days. The Logs screen has search, result tabs, a form filter, and entries that open under their row.<\/li>\n<li>Error emails carry a masked summary and a link to the log entry; repeats of the same kind within an hour are counted and summarised instead of mailed one by one.<\/li>\n<li>Redesigned admin screens in the WordPress look: the forms list (status tabs, search, bulk pause and resume), the mapping screen and Logs, with layouts for phones.<\/li>\n<li>Uninstall (when \"Delete data on uninstall\" is on) also removes the log table and the email throttle data.<\/li>\n<li>Requires WordPress 5.9 or later (PHP 8.0 was already required).<\/li>\n<\/ul>\n\n<p>Older releases: see changelog.txt in the plugin folder.<\/p>","raw_excerpt":"Send Contact Form 7 submissions to HubSpot: contacts, companies, deals, tickets or HubSpot forms. File uploads, consent checks and logs.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/ast.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/191192","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ast.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/ast.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/ast.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=191192"}],"author":[{"embeddable":true,"href":"https:\/\/ast.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/procoders"}],"wp:attachment":[{"href":"https:\/\/ast.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=191192"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/ast.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=191192"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/ast.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=191192"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/ast.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=191192"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/ast.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=191192"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/ast.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=191192"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}