> The option definitions. */ public function options(): array { return array( array( 'key' => 'token', 'type' => 'password', 'label' => __( 'Private app token', 'devplugins-custom-form-builder' ), 'required' => true, // One account token for the site, overridable per form. 'shared' => true, 'description' => __( 'Leave empty to use the token from the Integrations settings.', 'devplugins-custom-form-builder' ), ), array( 'key' => 'email_field', 'type' => 'field', 'label' => __( 'Email address comes from', 'devplugins-custom-form-builder' ), 'required' => true, ), array( 'key' => 'firstname_field', 'type' => 'field', 'label' => __( 'First name comes from', 'devplugins-custom-form-builder' ), ), array( 'key' => 'lastname_field', 'type' => 'field', 'label' => __( 'Last name comes from', 'devplugins-custom-form-builder' ), ), array( 'key' => 'phone_field', 'type' => 'field', 'label' => __( 'Phone comes from', 'devplugins-custom-form-builder' ), ), array( 'key' => 'company_field', 'type' => 'field', 'label' => __( 'Company comes from', 'devplugins-custom-form-builder' ), ), array( 'key' => 'extra', 'type' => 'textarea', 'label' => __( 'Other properties', 'devplugins-custom-form-builder' ), 'description' => __( 'One per line, written as hubspot_property = field_key.', 'devplugins-custom-form-builder' ), ), ); } /** * Returns where a submission should be delivered. * * @param Form $form Form being submitted. * @param array $config Stored values for that form. * * @return Webhook|null The endpoint, or null when there is nothing to send to. */ public function endpoint( Form $form, array $config ): ?Webhook { $token = $this->option( $config, 'token' ); if ( '' === $token ) { return null; } return $this->target( 'https://api.hubapi.com/crm/v3/objects/contacts', array( 'Authorization' => 'Bearer ' . $token ) ); } /** * Builds the contact record. * * @param IntegrationContext $context Submission being delivered. * @param array $config Stored values for the form. * * @return array The payload. */ public function payload( IntegrationContext $context, array $config ): array { $properties = array( 'email' => $context->email( $this->option( $config, 'email_field' ) ), ); $mapped = array( 'firstname' => 'firstname_field', 'lastname' => 'lastname_field', 'phone' => 'phone_field', 'company' => 'company_field', ); foreach ( $mapped as $property => $option ) { $value = $context->value( $this->option( $config, $option ) ); if ( '' !== $value ) { $properties[ $property ] = $value; } } foreach ( $this->extra( $config ) as $property => $key ) { $value = $context->value( $key ); if ( '' !== $value ) { $properties[ $property ] = $value; } } return array( 'properties' => $properties ); } /** * Returns whether a submission has anything worth sending. * * @param IntegrationContext $context Submission being delivered. * @param array $config Stored values for the form. * * @return bool True when the submission carries a usable address. */ public function should_send( IntegrationContext $context, array $config ): bool { return '' !== $context->email( $this->option( $config, 'email_field' ) ); } /** * Parses the extra property mapping. * * @param array $config Stored values for the form. * * @return array Field keys keyed by HubSpot property name. */ private function extra( array $config ): array { $mapping = array(); foreach ( preg_split( '/[\r\n]+/', $this->option( $config, 'extra' ) ) ?: array() as $line ) { if ( ! str_contains( (string) $line, '=' ) ) { continue; } list( $property, $key ) = explode( '=', (string) $line, 2 ); $property = strtolower( trim( $property ) ); $key = sanitize_key( trim( $key ) ); // HubSpot property names are lowercase letters, digits and underscores. if ( '' === $key || 1 !== preg_match( '/^[a-z0-9_]+$/', $property ) ) { continue; } $mapping[ $property ] = $key; } return $mapping; } }