PluginProbe
SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster / 1.6.2
SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster v1.6.2
2.7.0 2.6.0 trunk 1.1.0 1.1.4 1.2.1 1.2.2 1.2.3 1.2.5 1.2.9 1.3.1 1.3.2 1.5.0 1.5.1 1.5.4 1.5.7 1.5.8 1.5.9 1.6.2 1.6.5 1.6.8 1.7.2 1.7.4 1.7.5 1.7.9 All 43 releases
sellkit / includes / elementor / modules / optin / actions / utils / crm-trait.php

crm-trait.php in SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster 1.6.2, at includes/elementor/modules/optin/actions/utils/crm-trait.php

511 lines 14.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 defined( 'ABSPATH' ) || die();
4
5 use Sellkit_Elementor_Optin_Ajaxhandler as AjaxHandler;
6 use \Elementor\Repeater as Repeater;
7
8 /**
9 * Trait containing all the common or regularly used methods required for handling a CRM action.
10 */
11 trait Sellkit_Elementor_Optin_CRM {
12 /**
13 * Holds the name of User Agent.
14 *
15 * @access protected
16 * @var string
17 */
18 protected $user_agent = 'Sellkit';
19
20 /**
21 * Holds the name of User Agent.
22 *
23 * @access protected
24 * @var AjaxHandler|null
25 */
26 protected $ajax_handler = null;
27
28 /**
29 * Retrieve base URL for making remote request.
30 *
31 * @return string
32 *
33 * @access protected
34 * @since 1.5.0
35 */
36 abstract protected function get_base_url();
37
38 /**
39 * Retrieve header parameters for making remote requests.
40 *
41 * @return array
42 *
43 * @access protected
44 * @since 1.5.0
45 */
46 abstract protected function get_headers();
47
48 /**
49 * Retrieve parameters for making remote GET requests.
50 *
51 * @return array
52 *
53 * @access protected
54 * @since 1.5.0
55 */
56 abstract protected function get_get_request_args();
57
58 /**
59 * Get default remote fields of this specific CRM action.
60 *
61 * @return array Default remote fields. Must include two keys of "required" and "optional".
62 *
63 * @access protected
64 * @since 1.5.0
65 */
66 abstract protected function get_default_remote_fields();
67
68 /**
69 * Called by AJAX, retrieves the corresponding list for this CRM action.
70 *
71 * @param AjaxHandler $ajax_handler AJAX Handler instance.
72 * @param array $params Data passed by AJAX request.
73 * @return array Must always include one key "lists".
74 *
75 * @access public
76 * @since 1.5.0
77 */
78 abstract public function get_list( AjaxHandler $ajax_handler, $params );
79
80 /**
81 * Called by AJAX, retrieves the additional data for this CRM action.
82 *
83 * @param AjaxHandler $ajax_handler AJAX Handler instance.
84 * @param array $params Data passed by AJAX request.
85 * @return array Depending on the action it can contain multi keys( "custom_fields", "tags", etc.)
86 *
87 * @access public
88 * @since 1.5.0
89 */
90 abstract public function get_additional_data( AjaxHandler $ajax_handler, $params );
91
92 /**
93 * Create subscriber object from submitted data and form settings.
94 *
95 * @return array Subscriber data. The structure depends on the specific CRM action.
96 *
97 * @since 1.5.0
98 * @access protected
99 */
100 abstract protected function create_subscriber_object();
101
102 /**
103 * Get API parameters either from the controls or saved options of settings page.
104 *
105 * @param array $settings Control settings.
106 * @param string $param The name of parameter. Defaults to "key".
107 * @return string
108 *
109 * @since 1.5.0
110 * @access protected
111 */
112 protected function get_api_param( $settings, $param = 'key' ) {
113 $name = $this->get_name();
114 $api_key_source = $settings[ "{$name}_api_key_source" ];
115
116 if ( 'custom' === $api_key_source ) {
117 return $settings[ "{$name}_custom_api_{$param}" ];
118 }
119
120 $options = get_option( 'sellkit' );
121
122 if ( isset( $options[ "{$name}_api_{$param}" ] ) ) {
123 return $options[ "{$name}_api_{$param}" ];
124 }
125
126 return '';
127 }
128
129 /**
130 * Maps the values in field mapping control of this action, to the form fields.\
131 * Usually called inside of "create_subscriber_object" method.
132 *
133 * @return array
134 *
135 * @access protected
136 * @since 1.5.0
137 */
138 protected function get_field_mappings() {
139 $field_mappings = $this->ajax_handler->form['settings'][ $this->get_name() . '_fields_mapping' ];
140 $fields_repeater = $this->ajax_handler->form['settings']['fields'];
141 $form_fields = $this->ajax_handler->form_data['fields'];
142 $mapped_fields = [];
143
144 foreach ( $field_mappings as $item ) {
145 // Send warning about fields that are required by remote endpoint, but are missing or unrequired in the form.
146 $is_remote_required = array_key_exists( $item['remote_field'], $this->get_default_remote_fields()['required'] );
147
148 if ( $is_remote_required ) {
149 $field_index = array_search( $item['local_field'], array_column( $fields_repeater, '_id' ), true );
150 $is_local_exist = false !== $field_index;
151 $remote_label = $this->get_default_remote_fields()['required'][ $item['remote_field'] ];
152
153 if ( ! $is_local_exist ) {
154 $this->ajax_handler->add_response( 'admin_errors', $this->get_absent_require_notice( $remote_label ) );
155
156 } else {
157 $field_setting = $fields_repeater[ $field_index ];
158 $is_local_required = $field_setting['required'] && 'true' === $field_setting['required'];
159
160 if ( ! $is_local_required ) {
161 $this->ajax_handler->add_response( 'admin_errors', $this->get_make_require_notice( $remote_label ) );
162 }
163 }
164 }
165
166 // Go on with mapping process.
167 if ( empty( $item['local_field'] ) || empty( $item['remote_field'] ) ) {
168 continue;
169 }
170
171 $mapped_fields[ $item['remote_field'] ] = $form_fields[ $item['local_field'] ];
172 }
173
174 return $mapped_fields;
175 }
176
177 /**
178 * Send a GET request.
179 *
180 * @param string $endpoint The piece of URL to append to base URL.
181 * @param array $request_args Additional data to append to current request arguments.
182 * @return array The result of request, inside three keys "code", "body", "errors".
183 *
184 * @access protected
185 * @since 1.5.0
186 */
187 protected function send_get( $endpoint, $additional_args = [] ) {
188 $args = array_merge( $this->get_get_request_args(), $additional_args );
189 $response = wp_remote_get( $this->get_base_url() . $endpoint, $args );
190
191 return [
192 'code' => (int) wp_remote_retrieve_response_code( $response ),
193 'body' => json_decode( wp_remote_retrieve_body( $response ), true ),
194 ];
195 }
196
197 /**
198 * Send a POST request.
199 *
200 * @param string $endpoint The piece of URL to append to base URL.
201 * @param array $request_args Additional data to append to current request arguments.
202 * @param string $admin_error_key Key of admin_errors(if any) inside AJAX handler's response array.
203 * @return array The result of request, inside three keys "code", "body", "errors".
204 *
205 * @access protected
206 * @since 1.5.0
207 */
208 protected function send_post( $endpoint, $request_args = [], $admin_error_key = '' ) {
209 $response = wp_remote_post( $this->get_base_url() . $endpoint, $request_args );
210
211 $this->handle_errors( $response, $admin_error_key );
212
213 return [
214 'code' => (int) wp_remote_retrieve_response_code( $response ),
215 'body' => json_decode( wp_remote_retrieve_body( $response ), true ),
216 ];
217 }
218
219 /**
220 * Accepts the response of a remote request, collect its errors and loads them on AJAX response.
221 *
222 * @param array|\WP_Error $response The response of a remote request.
223 * @param string $admin_error_key Key of admin_errors(if any) inside AJAX handler's response array.
224 *
225 * @access private
226 * @since 1.5.0
227 */
228 private function handle_errors( $response, $admin_error_key ) {
229 $error = '';
230 $message_desc = esc_html__( ' (issued by endpoint)', 'sellkit' );
231
232 if ( is_wp_error( $response ) ) {
233 $error = implode( "</li><li>{$this->get_title()}: ", $response->get_error_messages() );
234
235 $this->ajax_handler->add_response( 'admin_errors', $error . $message_desc, $admin_error_key );
236 return;
237 }
238
239 $code = (int) wp_remote_retrieve_response_code( $response );
240
241 if ( ( $code < 200 || $code >= 300 ) ) {
242 $error = sprintf(
243 /* translators: 1: Action name, 2: response code, 3: error message (an unknown English string) */
244 esc_html__( '%1$s: Request error-%2$s -- %3$s', 'sellkit' ),
245 $this->get_title(),
246 $code,
247 wp_remote_retrieve_response_message( $response )
248 );
249 }
250
251 if ( ! empty( $error ) ) {
252 $this->ajax_handler->add_response( 'admin_errors', $error . $message_desc, $admin_error_key );
253 }
254 }
255
256 /**
257 * Get Client IP Address.
258 *
259 * @return string
260 *
261 * @since 1.5.0
262 * @access public
263 * @static
264 */
265 public static function get_client_ip() {
266 $ip_address = '';
267 $server_headers = [
268 'HTTP_CLIENT_IP',
269 'HTTP_X_FORWARDED_FOR',
270 'HTTP_X_FORWARDED',
271 'HTTP_FORWARDED_FOR',
272 'HTTP_FORWARDED',
273 'REMOTE_ADDR',
274 ];
275
276 // phpcs:disable WordPress.Security.ValidatedSanitizedInput
277 foreach ( $server_headers as $header ) {
278 if ( isset( $_SERVER[ $header ] ) ) {
279 $ip_address = $_SERVER[ $header ];
280 break;
281 }
282 }
283 // phpcs:enable
284
285 return $ip_address;
286 }
287
288 /**
289 * Ready made method that creates controls assocciated with API key of this CRM action.
290 *
291 * @param object $widget Widget instance.
292 * @param string $list_name Name of this CRM action's list (Account, Form, Campaign, etc.)
293 *
294 * @access protected
295 * @since 1.5.0
296 */
297 protected function add_api_controls( $widget, $list_name ) {
298 $action = $this->get_name();
299
300 $widget->add_control( "{$action}_api_key_source",
301 [
302 'label' => esc_html__( 'API key', 'sellkit' ),
303 'type' => 'select',
304 'default' => 'default',
305 'render_type' => 'ui',
306 'options' => [
307 'default' => esc_html__( 'Default', 'sellkit' ),
308 'custom' => esc_html__( 'Custom', 'sellkit' ),
309 ],
310 ]
311 );
312
313 $hint = sprintf(
314 /* translators: 1: html tag, 2: Action name, 3: html tags, 4: html tags */
315 esc_html__( '%1$sSet your %2$s API key in %3$s Sellkit Settings %4$s.', 'sellkit' ),
316 '<small>',
317 $this->get_title(),
318 sprintf( '<a target="_blank" href="%s">', admin_url() . 'admin.php?page=sellkit-settings&crm=' . $this->get_name() . '#/' ),
319 '<i class="fa fa-external-link-square"></i></a></small>'
320 );
321
322 $widget->add_control( "{$action}_api_key_msg",
323 [
324 'type' => 'raw_html',
325 'raw' => $hint,
326 'condition' => [ "{$action}_api_key_source" => 'default' ],
327 ]
328 );
329
330 $widget->add_control( "{$action}_custom_api_key",
331 [
332 'label' => esc_html__( 'Custom API Key', 'sellkit' ),
333 'type' => 'text',
334 'render_type' => 'ui',
335 /* translators: Action name */
336 'description' => sprintf( esc_html__( 'Enter your %s API key for only this form.', 'sellkit' ), $this->get_title() ),
337 'condition' => [ "{$action}_api_key_source" => 'custom' ],
338 ]
339 );
340
341 $widget->add_control( "{$action}_list",
342 [
343 'label' => $list_name,
344 'type' => 'select',
345 'render_type' => 'ui',
346 'conditions' => [
347 'relation' => 'or',
348 'terms' => [
349 [
350 'name' => "{$action}_custom_api_key",
351 'operator' => '!==',
352 'value' => '',
353 ],
354 [
355 'name' => "{$action}_api_key_source",
356 'operator' => '=',
357 'value' => 'default',
358 ],
359 ],
360 ],
361 ]
362 );
363 }
364
365 /**
366 * Ready made method that creates controls assocciated with field mapping for this CRM action.
367 *
368 * @param object $widget Widget instance.
369 *
370 * @access protected
371 * @since 1.5.0
372 */
373 protected function add_field_mapping_controls( $widget ) {
374 $action = $this->get_name();
375 $repeater = new Repeater();
376
377 $repeater->add_control( 'remote_field',
378 [
379 'label' => $this->get_title() . ' ' . esc_html__( 'Field', 'sellkit' ),
380 'type' => 'select',
381 'render_type' => 'ui',
382 'label_block' => false,
383 'options' => array_merge(
384 $this->get_default_remote_fields()['required'],
385 $this->get_default_remote_fields()['optional']
386 ),
387 ]
388 );
389
390 $repeater->add_control( 'local_field',
391 [
392 'label' => esc_html__( 'Form Field', 'sellkit' ),
393 'type' => 'select',
394 'render_type' => 'ui',
395 ]
396 );
397
398 $defaults = [];
399 foreach ( $this->get_default_remote_fields()['required'] as $key => $value ) {
400 $defaults[] = [
401 'remote_field' => $key,
402 'is_required' => true,
403 ];
404 }
405
406 $widget->add_control( "{$action}_fields_mapping",
407 [
408 'label' => esc_html__( 'Field Mapping', 'sellkit' ),
409 'type' => 'repeater',
410 'separator' => 'before',
411 'fields' => $repeater->get_controls(),
412 'default' => $defaults,
413 'conditions' => [
414 'terms' => [
415 [
416 'name' => "{$action}_list",
417 'operator' => '!in',
418 'value' => [ 'none', 'fetching', 'noList' ],
419 ],
420 ],
421 ],
422 ]
423 );
424 }
425
426 /**
427 * Ready made method that creates the control assocciated with tags for this CRM action.
428 *
429 * @param object $widget Widget instance.
430 *
431 * @access protected
432 * @since 1.5.0
433 */
434 protected function add_tag_control( $widget ) {
435 $action = $this->get_name();
436
437 $widget->add_control( "{$action}_tags",
438 [
439 'label' => esc_html__( 'Tags', 'sellkit' ),
440 'type' => 'select2',
441 'multiple' => true,
442 'label_block' => true,
443 'render_type' => 'ui',
444 'conditions' => [
445 'terms' => [
446 [
447 'name' => "{$action}_list",
448 'operator' => '!in',
449 'value' => [ 'none', 'fetching', 'noList' ],
450 ],
451 ],
452 ],
453 ]
454 );
455 }
456
457 /**
458 * Creates and returns a text that notifies the user that a field should be made required.
459 *
460 * @param string $field_label Label of the field.
461 * @return string
462 *
463 * @access protected
464 * @since 1.5.0
465 */
466 protected function get_make_require_notice( $field_label ) {
467 return sprintf(
468 /* translators: 1: Action name 2: Field name */
469 esc_attr__( '%1$s: %2$s is required by api endpoint, but the corresponding field is not made required in your form.', 'sellkit' ),
470 $this->get_title(),
471 $field_label
472 );
473 }
474
475 /**
476 * Creates and returns a text that notifies the user that a remote-required field is mapped to none of local form fields.
477 *
478 * @param string $field_label Label of the field.
479 * @return string
480 *
481 * @access protected
482 * @since 1.5.0
483 */
484 protected function get_absent_require_notice( $field_label ) {
485 return sprintf(
486 /* translators: 1: Action name 2: Field name */
487 esc_attr__( '%1$s: %2$s is required by api endpoint, but it is not mapped to any field in your form.', 'sellkit' ),
488 $this->get_title(),
489 $field_label
490 );
491 }
492
493 /**
494 * Creates and returns a text that notifies the user that not a valid list is selected fo this CRM action.
495 *
496 * @param string $list_name Label of the list (Account, Form, Campaign, etc.).
497 * @return string
498 *
499 * @access protected
500 * @since 1.5.0
501 */
502 protected function get_invalid_list_message( $list_name ) {
503 return sprintf(
504 /* translators: 1: Action name 2: List name */
505 esc_html__( '%1$s: Invalid %2$s is selected.', 'sellkit' ),
506 $this->get_title(),
507 $list_name
508 );
509 }
510 }
511