PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 16.1-beta.2
Jetpack – WP Security, Backup, Speed, & Growth v16.1-beta.2
16.1.2 16.2-a.1 16.1.1 16.1 16.1-beta 16.1-beta.2 16.1-beta.3 16.1-a.5 16.1-a.3 16.0.1 16.1-a.1 16.0 16.0-beta 16.0-a.7 16.0-a.5 15.9.1 16.0-a.3 16.0-a.1 15.9 15.9-beta 15.9-a.7 15.9-a.5 15.9-a.3 15.9-a.1 15.8 15.8-beta 15.8-a.7 15.8-a.5 5.2.5 5.3.4 5.4.4 5.5.5 5.6.5 5.7.5 5.8.4 5.9.4 6.0.4 6.1 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 6.2 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.3 6.3.1 6.3.2 6.3.3 6.3.4 6.3.5 6.3.6 6.3.7 6.4 6.4.1 6.4.2 6.4.3 6.4.4 6.4.5 6.4.6 6.5 6.5.1 6.5.2 6.5.3 6.5.4 6.6 6.6.1 6.6.2 6.6.3 6.6.4 6.6.5 6.7 6.7.1 6.7.2 6.7.3 6.7.4 6.8 6.8.1 6.8.2 6.8.3 6.8.4 6.8.5 6.9 6.9.1 6.9.2 6.9.3 6.9.4 7.0 7.0.1 7.0.2 7.0.3 7.0.4 7.0.5 7.1 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2 7.2.1 7.2.1.1 7.2.2 7.2.3 7.2.4 7.2.5 7.3 7.3.0.1 7.3.1 7.3.1.1 7.3.2 7.3.3 7.3.4 7.3.5 7.4 7.4.1 7.4.2 7.4.3 7.4.4 7.4.5 7.5 7.5.0.1 7.5.1 7.5.2 7.5.3 7.5.4 7.5.5 7.5.6 7.5.7 7.6 7.6.1 7.6.2 7.6.3 7.6.4 7.7 7.7.1 7.7.2 7.7.3 7.7.4 7.7.5 7.7.6 7.8 7.8.1 7.8.2 7.8.3 7.8.4 7.9 7.9.1 7.9.2 7.9.3 7.9.4 8.0 8.0.1 8.0.2 8.0.3 8.1 8.1.1 8.1.2 8.1.3 8.1.4 8.2 8.2.0.1 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.2.6 8.3 8.3.1 8.3.2 8.3.3 8.4 8.4.1 8.4.2 8.4.3 8.4.4 8.4.5 8.5 8.5.1 8.5.2 8.5.3 8.6 8.6.1 8.6.2 8.6.3 8.6.4 8.7 8.7.0.1 8.7.1 8.7.2 8.7.3 8.7.4 8.8 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.9 8.9.1 8.9.2 8.9.3 8.9.4 9.0 9.0.1 9.0.2 9.0.3 9.0.4 9.0.5 9.1 9.1.1 9.1.2 9.1.3 9.2 9.2.1 9.2.2 9.2.3 9.2.4 9.3 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.4 9.4.1 9.4.2 9.4.3 9.4.4 9.5 9.5.1 9.5.2 9.5.3 9.5.4 9.5.5 9.6 9.6.1 9.6.2 9.6.3 9.6.4 9.7 9.7.1 9.7.2 15.7-beta.2 9.7.3 15.7.1 9.8 15.8-a.1 9.8.1 15.8-a.3 9.8.2 2.0.9 9.8.3 2.1.7 9.9 2.2.10 9.9.1 2.3.10 9.9.2 2.4.7 9.9.3 2.5.5 2.6.6 2.7.5 2.8.5 2.9.6 3.0.6 3.1.5 3.2.5 3.3.6 3.4.6 3.5.6 3.6.4 3.7.5 3.8.5 3.9.10 4.0.7 4.1.4 4.2.5 4.3.5 4.4.5 4.5.3 4.6.3 4.7.4 4.8.5 4.9.3 5.0.3 5.1.4 trunk 10.0 10.0.1 10.0.2 10.1 10.1.1 10.1.2 10.2 10.2.1 10.2.2 10.2.3 10.3 10.3.1 10.3.2 10.4 10.4.1 10.4.2 10.5 10.5.1 10.5.2 10.5.3 10.6 10.6.1 10.6.2 10.7 10.7.1 10.7.2 10.8 10.8.1 10.8.2 10.9 10.9.1 10.9.2 10.9.3 11.0 11.0.1 11.0.2 11.1 11.1.1 11.1.2 11.1.3 11.1.4 11.2 11.2.1 11.2.2 11.3 11.3.1 11.3.2 11.3.3 11.3.4 11.4 11.4.1 11.4.2 11.5 11.5.1 11.5.2 11.5.3 11.6 11.6.1 11.6.2 11.7 11.7.1 11.7.2 11.7.3 11.8 11.8.3 11.8.4 11.8.5 11.8.6 11.9 11.9.1 11.9.2 11.9.3 12.0 12.0.1 12.0.2 12.1 12.1.1 12.1.2 12.2 12.2.1 12.2.2 12.3 12.3.1 12.4 12.4.1 12.5 12.5.1 12.6 12.6.1 12.6.2 12.6.3 12.7 12.7.1 12.7.2 12.8 12.8.1 12.8.2 12.9 12.9.1 12.9.2 12.9.3 12.9.4 13.0 13.0.1 13.1 13.1.1 13.1.2 13.1.3 13.1.4 13.2 13.2.1 13.2.2 13.2.3 13.3 13.3.1 13.3.2 13.4 13.4.1 13.4.2 13.4.3 13.4.4 13.5 13.5.1 13.6 13.6.1 13.7 13.7.1 13.8 13.8.1 13.8.2 13.9 13.9.1 14.0 14.1 14.2 14.2.1 14.3 14.4 14.4.1 14.5 14.6 14.7 14.8 14.9 14.9.1 15.0 15.0.1 15.0.2 15.1 15.1.1 15.2 15.3 15.3.1 15.4 15.5 15.6 15.7 15.7-a.1 15.7-a.3 15.7-a.5 15.7-a.7 15.7-beta
jetpack / jetpack_vendor / automattic / jetpack-forms / src / service / class-hostinger-reach-integration.php
jetpack / jetpack_vendor / automattic / jetpack-forms / src / service Last commit date
class-form-webhooks.php 1 month ago class-google-drive.php 9 months ago class-hostinger-reach-integration.php 9 months ago class-mailpoet-integration.php 1 month ago class-post-to-url.php 1 month ago
class-hostinger-reach-integration.php
256 lines
1 <?php
2 /**
3 * Hostinger Reach Integration for Jetpack Contact Forms.
4 *
5 * @package automattic/jetpack
6 */
7
8 namespace Automattic\Jetpack\Forms\Service;
9
10 use Automattic\Jetpack\Forms\ContactForm\Feedback;
11
12 /**
13 * Class Hostinger_Reach_Integration
14 *
15 * Scaffolding for handling integration with Hostinger Reach for Jetpack Contact Forms.
16 * Public API docs are limited; this class mirrors the structure of MailPoet_Integration
17 * and will be implemented once the Hostinger Reach plugin APIs are confirmed.
18 */
19 class Hostinger_Reach_Integration {
20 /**
21 * Placeholder for a Hostinger Reach API instance, if needed later.
22 *
23 * @var mixed
24 */
25 protected static $hostinger_api = null;
26
27 /**
28 * Submit contact to Hostinger Reach.
29 *
30 * @param mixed $api_handler Reach API handler.
31 * @param array $subscriber_data Associative array: email, first_name, last_name.
32 * @param string $group_name Target group name.
33 * @return void
34 */
35 protected static function submit_contact( $api_handler, array $subscriber_data, $group_name ) {
36 if ( ! $api_handler || empty( $subscriber_data['email'] ) ) {
37 return;
38 }
39
40 $subscriber_data['group'] = $group_name;
41 $api_handler->post_contact( $subscriber_data );
42 }
43
44 /**
45 * Get the Hostinger Reach API instance.
46 *
47 * @return mixed
48 */
49 protected static function get_api() {
50 if (
51 null === self::$hostinger_api
52 // @phan-suppress-next-line PhanUndeclaredClassReference
53 && class_exists( \Hostinger\Reach\Api\Handlers\ReachApiHandler::class )
54 // @phan-suppress-next-line PhanUndeclaredClassReference
55 && class_exists( \Hostinger\Reach\Functions::class )
56 // @phan-suppress-next-line PhanUndeclaredClassReference
57 && class_exists( \Hostinger\Reach\Api\ApiKeyManager::class )
58 ) {
59 // @phan-suppress-next-line PhanUndeclaredClassMethod
60 self::$hostinger_api = new \Hostinger\Reach\Api\Handlers\ReachApiHandler(
61 // @phan-suppress-next-line PhanUndeclaredClassMethod
62 new \Hostinger\Reach\Functions(),
63 // @phan-suppress-next-line PhanUndeclaredClassMethod
64 new \Hostinger\Reach\Api\ApiKeyManager()
65 );
66 }
67
68 return self::$hostinger_api;
69 }
70
71 /**
72 * Get group name from form attributes, falling back to 'Jetpack Forms'.
73 *
74 * @param mixed $form Contact form instance.
75 * @return string
76 */
77 protected static function get_group_name( $form ) {
78 $group_name = ! empty( $form->attributes['hostingerReach']['groupName'] ?? '' )
79 ? trim( $form->attributes['hostingerReach']['groupName'] )
80 : 'Jetpack Forms';
81 return $group_name;
82 }
83
84 /**
85 * Extract subscriber data (email, first_name, last_name) using Feedback API (v2 storage).
86 *
87 * @param Feedback $feedback Feedback object for the submission.
88 * @return array Associative array with at least 'email', optionally 'first_name', 'last_name'. Empty array if no email found.
89 */
90 protected static function get_subscriber_data( $feedback ) {
91 if ( ! $feedback->get_author_email() ) {
92 return array();
93 }
94
95 $subscriber_data = array();
96 $subscriber_data['email'] = $feedback->get_author_email();
97
98 if ( $feedback->get_field_value_by_label( 'First Name' ) ) {
99 $subscriber_data['name'] = $feedback->get_field_value_by_label( 'First Name' );
100 } elseif ( $feedback->get_field_value_by_form_field_id( 'firstname' ) ) {
101 $subscriber_data['name'] = $feedback->get_field_value_by_form_field_id( 'firstname' );
102 } elseif ( $feedback->get_field_value_by_form_field_id( 'first-name' ) ) {
103 $subscriber_data['name'] = $feedback->get_field_value_by_form_field_id( 'first-name' );
104 }
105 if ( $feedback->get_field_value_by_label( 'Last Name' ) ) {
106 $subscriber_data['surname'] = $feedback->get_field_value_by_label( 'Last Name' );
107 } elseif ( $feedback->get_field_value_by_form_field_id( 'lastname' ) ) {
108 $subscriber_data['surname'] = $feedback->get_field_value_by_form_field_id( 'lastname' );
109 } elseif ( $feedback->get_field_value_by_form_field_id( 'last-name' ) ) {
110 $subscriber_data['surname'] = $feedback->get_field_value_by_form_field_id( 'last-name' );
111 }
112
113 return $subscriber_data;
114 }
115
116 /**
117 * Extract subscriber data (email, first_name, last_name) from legacy field data (v1 storage).
118 *
119 * @param array $fields Collection of Contact_Form_Field instances.
120 * @return array Associative array with at least 'email', optionally 'first_name', 'last_name'. Empty array if no email found.
121 */
122 protected static function get_subscriber_data_from_fields( $fields ) {
123 // Try and get the form from any of the fields
124 $form = null;
125 foreach ( $fields as $field ) {
126 if ( ! empty( $field->form ) ) {
127 $form = $field->form;
128 break;
129 }
130 }
131 if ( ! $form || ! is_a( $form, 'Automattic\\Jetpack\\Forms\\ContactForm\\Contact_Form' ) ) {
132 return array();
133 }
134
135 $subscriber_data = array();
136
137 foreach ( $form->fields as $field ) {
138 $id = strtolower( str_replace( array( ' ', '_' ), '', $field->get_attribute( 'id' ) ) );
139 $label = strtolower( str_replace( array( ' ', '_' ), '', $field->get_attribute( 'label' ) ) );
140
141 if ( ! is_string( $field->value ) ) {
142 continue;
143 }
144
145 $value = trim( $field->value );
146
147 if ( ( $id === 'email' || $label === 'email' ) && ! empty( $value ) ) {
148 $subscriber_data['email'] = $value;
149 } elseif ( ( $id === 'firstname' || $label === 'firstname' ) && ! empty( $value ) ) {
150 $subscriber_data['name'] = $value;
151 } elseif ( ( $id === 'lastname' || $label === 'lastname' ) && ! empty( $value ) ) {
152 $subscriber_data['surname'] = $value;
153 }
154 }
155
156 if ( empty( $subscriber_data['email'] ) ) {
157 return array();
158 }
159
160 return $subscriber_data;
161 }
162
163 /**
164 * Check if submission has consent when required.
165 *
166 * @param Feedback $feedback Feedback object for the submission.
167 * @param mixed $form Contact form instance.
168 * @param bool $is_v2 Whether the data comes from v2 storage.
169 * @return bool True if consent is present or not required; false otherwise.
170 */
171 protected static function has_consent( $feedback, $form, $is_v2 ) {
172 if ( $is_v2 ) {
173 if ( $feedback->has_field_type( 'consent' ) && ! $feedback->has_consent() ) {
174 return false;
175 }
176 return true;
177 }
178
179 $consent_field = null;
180 if ( is_object( $form ) && is_array( $form->fields ) ) {
181 foreach ( $form->fields as $form_field ) {
182 if ( 'consent' === $form_field->get_attribute( 'type' ) ) {
183 $consent_field = $form_field;
184 break;
185 }
186 }
187 }
188 if ( $consent_field ) {
189 $consent_type = strtolower( (string) $consent_field->get_attribute( 'consenttype' ) );
190 if ( 'explicit' === $consent_type && ! $consent_field->value ) {
191 return false;
192 }
193 }
194
195 return true;
196 }
197
198 /**
199 * Handle Hostinger Reach integration after feedback post is inserted.
200 *
201 * For now, this only validates preconditions and returns early; real actions will be implemented later.
202 *
203 * @param int $post_id The post ID for the feedback CPT.
204 * @param array $fields Collection of Contact_Form_Field instances.
205 * @param bool $is_spam Whether the submission is spam.
206 */
207 public static function handle_hostinger_reach_integration( $post_id, $fields, $is_spam ) {
208 if ( $is_spam ) {
209 return;
210 }
211
212 // Try and get the form from any of the fields
213 $form = null;
214 foreach ( $fields as $field ) {
215 if ( ! empty( $field->form ) ) {
216 $form = $field->form;
217 break;
218 }
219 }
220 if ( ! $form || ! is_a( $form, 'Automattic\\Jetpack\\Forms\\ContactForm\\Contact_Form' ) ) {
221 return;
222 }
223
224 // Feature is toggled per-form.
225 if ( empty( $form->attributes['hostingerReach']['enabledForForm'] ?? null ) ) {
226 return;
227 }
228
229 $feedback = Feedback::get( $post_id );
230 if ( ! $feedback ) {
231 return;
232 }
233
234 $api_handler = self::get_api();
235 if ( ! $api_handler ) {
236 return;
237 }
238
239 // Respect consent if a consent field exists.
240 $post = get_post( $post_id );
241 $is_v2_data = ( $post && $post->post_mime_type === 'v2' );
242 if ( ! self::has_consent( $feedback, $form, $is_v2_data ) ) {
243 return;
244 }
245
246 $subscriber_data = $is_v2_data ? self::get_subscriber_data( $feedback ) : self::get_subscriber_data_from_fields( $fields );
247 if ( empty( $subscriber_data ) ) {
248 return;
249 }
250
251 $group_name = self::get_group_name( $form );
252
253 self::submit_contact( $api_handler, $subscriber_data, $group_name );
254 }
255 }
256