diff --git a/projects/packages/forms/changelog/add-forms-backend-mailpoet-integration b/projects/packages/forms/changelog/add-forms-backend-mailpoet-integration new file mode 100644 index 0000000000000..e45e4ef65578e --- /dev/null +++ b/projects/packages/forms/changelog/add-forms-backend-mailpoet-integration @@ -0,0 +1,4 @@ +Significance: minor +Type: added + +Forms: Add MailPoet backend integration. diff --git a/projects/packages/forms/src/contact-form/class-contact-form-plugin.php b/projects/packages/forms/src/contact-form/class-contact-form-plugin.php index 4866247d41466..65f2842864875 100644 --- a/projects/packages/forms/src/contact-form/class-contact-form-plugin.php +++ b/projects/packages/forms/src/contact-form/class-contact-form-plugin.php @@ -11,6 +11,7 @@ use Automattic\Jetpack\Constants; use Automattic\Jetpack\Extensions\Contact_Form\Contact_Form_Block; use Automattic\Jetpack\Forms\Jetpack_Forms; +use Automattic\Jetpack\Forms\Service\MailPoet_Integration; use Automattic\Jetpack\Forms\Service\Post_To_Url; use Automattic\Jetpack\Status; use Automattic\Jetpack\Terms_Of_Service; @@ -301,6 +302,16 @@ protected function __construct() { } self::register_contact_form_blocks(); + + // Register MailPoet integration hook after the class is loaded. + if ( Jetpack_Forms::is_mailpoet_enabled() ) { + add_action( + 'grunion_after_feedback_post_inserted', + array( MailPoet_Integration::class, 'handle_mailpoet_integration' ), + 15, + 4 + ); + } } /** @@ -1383,6 +1394,7 @@ public function process_form_submission() { if ( ! empty( $form->attributes['salesforceData'] ) || ! empty( $form->attributes['postToUrl'] ) ) { Post_To_Url::init(); } + // Process the form return $form->process_submission(); } diff --git a/projects/packages/forms/src/contact-form/class-contact-form.php b/projects/packages/forms/src/contact-form/class-contact-form.php index 20666d36ab249..7fa63b9f275e3 100644 --- a/projects/packages/forms/src/contact-form/class-contact-form.php +++ b/projects/packages/forms/src/contact-form/class-contact-form.php @@ -179,6 +179,7 @@ public function __construct( $attributes, $content = null, $set_id = true ) { 'customThankyouMessage' => __( 'Thank you for your submission!', 'jetpack-forms' ), // The message to show when customThankyou is set to 'message'. 'customThankyouRedirect' => '', // The URL to redirect to when customThankyou is set to 'redirect'. 'jetpackCRM' => true, // Whether Jetpack CRM should store the form submission. + 'connectMailPoet' => false, // Whether to send contact to MailPoet. 'className' => null, 'postToUrl' => null, 'salesforceData' => null, diff --git a/projects/packages/forms/src/service/class-mailpoet-integration.php b/projects/packages/forms/src/service/class-mailpoet-integration.php new file mode 100644 index 0000000000000..424a84fa8ebc1 --- /dev/null +++ b/projects/packages/forms/src/service/class-mailpoet-integration.php @@ -0,0 +1,178 @@ +getLists(); + // Look for an existing list with the given name (not deleted) + foreach ( $lists as $list ) { + if ( $list['name'] === $list_name && empty( $list['deleted_at'] ) ) { + return $list['id']; + } + } + // Not found, create it + $new_list = $mailpoet_api->addList( + array( + 'name' => $list_name, + 'description' => $list_description, + ) + ); + return $new_list['id']; + } catch ( \Exception $e ) { + return null; + } + } + + /** + * Add a subscriber to a MailPoet list. + * + * @param mixed $mailpoet_api The MailPoet API instance. + * @param string $list_id The MailPoet list ID. + * @param array $subscriber_data Associative array with at least 'email', optionally 'first_name', 'last_name'. + * @return array|null Subscriber data on success, or null on failure. + */ + protected static function add_subscriber_to_list( $mailpoet_api, $list_id, $subscriber_data ) { + try { + $subscriber = $mailpoet_api->addSubscriber( + $subscriber_data, + array( $list_id ) + ); + return $subscriber; + } catch ( \Exception $e ) { + return null; + } + } + + /** + * Extract subscriber data (email, first_name, last_name) from form fields. + * + * @param array $fields Collection of Contact_Form_Field instances. + * @return array Associative array with at least 'email', optionally 'first_name', 'last_name'. Empty array if no email found. + */ + protected static function get_subscriber_data_from_fields( $fields ) { + // Try and get the form from any of the fields + $form = null; + foreach ( $fields as $field ) { + if ( ! empty( $field->form ) ) { + $form = $field->form; + break; + } + } + if ( ! $form || ! is_a( $form, 'Automattic\Jetpack\Forms\ContactForm\Contact_Form' ) ) { + return array(); + } + + $subscriber_data = array(); + foreach ( $form->fields as $field ) { + $id = strtolower( str_replace( array( ' ', '_' ), '', $field->get_attribute( 'id' ) ) ); + $label = strtolower( str_replace( array( ' ', '_' ), '', $field->get_attribute( 'label' ) ) ); + $value = trim( $field->value ); + + if ( ( $id === 'email' || $label === 'email' ) && ! empty( $value ) ) { + $subscriber_data['email'] = $value; + } elseif ( ( $id === 'firstname' || $label === 'firstname' ) && ! empty( $value ) ) { + $subscriber_data['first_name'] = $value; + } elseif ( ( $id === 'lastname' || $label === 'lastname' ) && ! empty( $value ) ) { + $subscriber_data['last_name'] = $value; + } + } + + if ( empty( $subscriber_data['email'] ) ) { + return array(); + } + + return $subscriber_data; + } + + /** + * Handle MailPoet integration after feedback post is inserted. + * + * @param int $post_id The post ID for the feedback CPT. + * @param array $fields Collection of Contact_Form_Field instances. + * @param bool $is_spam Whether the submission is spam. + */ + public static function handle_mailpoet_integration( $post_id, $fields, $is_spam ) { + if ( $is_spam ) { + return; + } + + // Try and get the form from any of the fields + $form = null; + foreach ( $fields as $field ) { + if ( ! empty( $field->form ) ) { + $form = $field->form; + break; + } + } + if ( ! $form || ! is_a( $form, 'Automattic\Jetpack\Forms\ContactForm\Contact_Form' ) ) { + return; + } + + if ( empty( $form->attributes['connectMailPoet'] ) ) { + return; + } + + $mailpoet_api = self::get_api(); + if ( ! $mailpoet_api ) { + // MailPoet is not active or not loaded. + return; + } + + $list_id = self::get_or_create_list_id( $mailpoet_api ); + if ( ! $list_id ) { + // Could not get or create the list; bail out. + return; + } + + $subscriber_data = self::get_subscriber_data_from_fields( $fields ); + if ( empty( $subscriber_data ) ) { + // Email is required for MailPoet subscribers. + return; + } + + self::add_subscriber_to_list( $mailpoet_api, $list_id, $subscriber_data ); + } +} diff --git a/projects/packages/forms/tests/php/contact-form/Contact_Form_Test.php b/projects/packages/forms/tests/php/contact-form/Contact_Form_Test.php index fe63c94439a10..e1e99a9653c64 100644 --- a/projects/packages/forms/tests/php/contact-form/Contact_Form_Test.php +++ b/projects/packages/forms/tests/php/contact-form/Contact_Form_Test.php @@ -2959,6 +2959,7 @@ public function test_get_instance_from_jwt_returns_with_all_attribute_data() { 'hiddenField2' => 'value2', ), // Hidden fields to include in the form. 'stepTransition' => 'fade-slide', + 'connectMailPoet' => false, ); // Add a widget ID to the attributes for testing. $expected_attributes = $attributes;