Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: added

Forms: Add MailPoet backend integration.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
);
}
}

/**
Expand Down Expand Up @@ -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();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
178 changes: 178 additions & 0 deletions projects/packages/forms/src/service/class-mailpoet-integration.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
<?php
/**
* MailPoet Integration for Jetpack Contact Forms.
*
* @package automattic/jetpack
*/

namespace Automattic\Jetpack\Forms\Service;

/**
* Class MailPoet_Integration
*
* Handles integration with MailPoet for Jetpack Contact Forms.
*/
class MailPoet_Integration {
/**
* MailPoet API instance
*
* @var mixed
*/
protected static $mailpoet_api = null;

/**
* Get the MailPoet API instance (v1), instantiating if necessary.
*
* @return mixed
*/
protected static function get_api() {
if ( null === self::$mailpoet_api && class_exists( '\MailPoet\API\API' ) ) {
// @phan-suppress-next-line PhanUndeclaredClassMethod
self::$mailpoet_api = \MailPoet\API\API::MP( 'v1' );
}
return self::$mailpoet_api;
}

/**
* Get or create a MailPoet list for Jetpack Forms.
*
* @param mixed $mailpoet_api The MailPoet API instance.
* @param string|null $list_name Optional. The name of the list to get or create. Defaults to 'Jetpack Form Subscribers'.
* @return string|null List ID or null on failure.
*/
protected static function get_or_create_list_id( $mailpoet_api, $list_name = null ) {
$default_list_name = 'Jetpack Form Subscribers';
$default_list_description = 'Subscribers from Jetpack Forms';
$list_name = $list_name ? $list_name : $default_list_name;
$list_description = $list_name === $default_list_name ? $default_list_description : $list_name;
try {
$lists = $mailpoet_api->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 );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading