PluginProbe
Hostinger Tools / 2.2.2
Hostinger Tools v2.2.2
3.0.77 3.0.76 3.0.75 3.0.74 3.0.73 3.0.72 3.0.71 3.0.70 3.0.69 3.0.68 3.0.67 3.0.66 1.8.1 1.8.2 1.8.3 1.9.1 1.9.4 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.0.0 2.0.1 2.0.4 All 108 releases
hostinger / includes / Surveys / Surveys.php

Surveys.php in Hostinger Tools 2.2.2, at includes/Surveys/Surveys.php

595 lines 19.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Hostinger\Surveys;
4
5 use Hostinger\Config;
6 use Hostinger\Helper;
7 use Hostinger\Settings;
8 use Hostinger\Surveys\Questions;
9 use Hostinger\Surveys\Rest\Rest;
10
11 defined( 'ABSPATH' ) || exit;
12
13 class Surveys {
14 public const CACHE_THREE_HOURS = 3600 * 3;
15 public const TIME_15_MINUTES = 900;
16 public const TIME_24_HOURS = 86400;
17 public const CLIENT_SURVEY_IDENTIFIER = 'customer_satisfaction_score';
18 public const CLIENT_WOO_COMPLETED_ACTIONS = 'woocommerce_task_list_tracked_completed_tasks';
19 public const WOO_SURVEY_IDENTIFIER = 'wordpress_woocommerce_onboarding';
20 public const AI_ONBOARDING_SURVEY_IDENTIFIER = 'wordpress_ai_onboarding';
21 public const AFFILIATE_SURVEY_IDENTIFIER = 'wordpress_amazon_affiliate';
22 public const PREBUILD_WEBSITE_SURVEY_IDENTIFIER = 'wordpress_prebuild_website';
23 public const SUBMITTED_SURVEY_TRANSIENT = 'submitted_survey_transient';
24 public const SURVEY_QUESTIONS_TRANSIENT_REQUEST = 'survey_questions_transient_request';
25 public const SURVEY_QUESTIONS_TRANSIENT_RESPONSE = 'survey_questions_transient_response';
26 public const IS_CLIENT_ELIGIBLE_TRANSIENT_RESPONSE = 'client_eligibility_transient_response';
27 public const IS_CLIENT_ELIGIBLE_TRANSIENT_REQUEST = 'survey_questions_transient_request';
28 public const LOCATION_SLUG = 'location';
29 public const WOOCOMMERCE_PAGES = array(
30 '/wp-admin/admin.php?page=wc-admin',
31 '/wp-admin/edit.php?post_type=shop_order',
32 '/wp-admin/admin.php?page=wc-admin&path=/customers',
33 '/wp-admin/edit.php?post_type=shop_coupon&legacy_coupon_menu=1',
34 '/wp-admin/admin.php?page=wc-admin&path=/marketing',
35 '/wp-admin/admin.php?page=wc-reports',
36 '/wp-admin/admin.php?page=wc-settings',
37 '/wp-admin/admin.php?page=wc-status',
38 '/wp-admin/admin.php?page=wc-admin&path=/extensions',
39 '/wp-admin/edit.php?post_type=product',
40 '/wp-admin/post-new.php?post_type=product',
41 '/wp-admin/edit.php?post_type=product&page=product-reviews',
42 '/wp-admin/edit.php?post_type=product&page=product_attributes',
43 '/wp-admin/edit-tags.php?taxonomy=product_cat&post_type=product',
44 '/wp-admin/edit-tags.php?taxonomy=product_tag&post_type=product',
45 '/wp-admin/admin.php?page=wc-admin&path=/analytics/overview',
46 '/wp-admin/admin.php?page=wc-admin',
47 );
48
49 private Config $config_handler;
50 private Settings $settings;
51 private Helper $helper;
52 private Questions $survey_questions;
53 private Rest $surveys_rest;
54
55 public function __construct(
56 Settings $settings,
57 Helper $helper,
58 Config $config_handler,
59 Questions $survey_questions,
60 Rest $surveys_rest
61 ) {
62 $this->settings = $settings;
63 $this->helper = $helper;
64 $this->config_handler = $config_handler;
65 $this->survey_questions = $survey_questions;
66 $this->surveys_rest = $surveys_rest;
67 }
68
69 public function is_woocommerce_admin_page(): bool {
70 if ( ! isset( $_SERVER['REQUEST_URI'] ) ) {
71 return false;
72 }
73
74 $current_uri = sanitize_text_field( $_SERVER['REQUEST_URI'] );
75
76 if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
77 return false;
78 }
79
80 if ( isset( $current_uri ) && strpos( $current_uri, '/wp-json/' ) !== false ) {
81 return false;
82 }
83
84 foreach ( self::WOOCOMMERCE_PAGES as $page ) {
85 if ( strpos( $current_uri, $page ) !== false ) {
86 return true;
87 }
88 }
89
90 return false;
91 }
92
93 public function is_content_generation_survey_enabled(): bool {
94 if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
95 return false;
96 }
97
98 $not_submitted = ! get_transient( self::SUBMITTED_SURVEY_TRANSIENT );
99 $not_completed = ! $this->settings->get_setting( 'feedback_survey_completed' );
100 $content_published = $this->settings->get_setting( 'content_published' );
101 $is_client_eligible = $this->is_client_eligible();
102 $is_hostinger_page = $this->helper->is_hostinger_admin_page();
103
104 if ( ! $is_hostinger_page || empty( $this->get_survey_questions() ) ) {
105 return false;
106 }
107
108 return $not_submitted && $not_completed && $content_published && $is_client_eligible;
109 }
110
111 public function is_woocommerce_survey_enabled(): bool {
112
113 if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
114 return false;
115 }
116 $not_submitted = ! get_transient( self::SUBMITTED_SURVEY_TRANSIENT );
117 $not_completed = ! $this->settings->get_setting( 'woocommerce_survey_completed' );
118 $is_woocommerce_page = $this->is_woocommerce_admin_page();
119 $default_woocommerce_completed = $this->helper->default_woocommerce_survey_completed();
120 $oldest_product_date = $this->get_oldest_product_date();
121 $seven_days_ago = strtotime( '-7 days' );
122 $is_client_eligible = $this->is_client_eligible();
123
124 if ( empty( $this->get_survey_questions() ) || $oldest_product_date < $seven_days_ago ) {
125 return false;
126 }
127
128 return $not_submitted && $not_completed && $is_woocommerce_page && $default_woocommerce_completed && $is_client_eligible;
129 }
130
131 public function is_ai_onboarding_survey_enabled(): bool {
132 if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
133 return false;
134 }
135
136 $first_login_at = strtotime( get_option( 'hostinger_first_login_at', time() ) );
137 $not_submitted = ! get_transient( self::SUBMITTED_SURVEY_TRANSIENT );
138 $not_completed = ! $this->settings->get_setting( 'ai_onboarding_survey_completed' );
139 $is_client_eligible = $this->is_client_eligible();
140 $is_ai_onboarding_passed = $this->settings->get_setting( 'ai_onboarding' );
141 $is_hostinger_admin_page = $this->helper->is_hostinger_admin_page();
142
143 if ( ! $is_ai_onboarding_passed || empty( $this->get_survey_questions() ) ) {
144 return false;
145 }
146
147 if ( $first_login_at && ! $this->is_time_elapsed( $first_login_at, self::TIME_15_MINUTES ) ) {
148 return false;
149 }
150
151 return $not_submitted && $not_completed && $is_client_eligible && $is_hostinger_admin_page;
152 }
153
154 public function is_affiliate_survey_enabled(): bool {
155
156 if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
157 return false;
158 }
159
160 $not_submitted = ! get_transient( self::SUBMITTED_SURVEY_TRANSIENT );
161 $not_completed = ! $this->settings->get_setting( 'affiliate_survey_completed' );
162 $affiliate_links_exsists = $this->settings->get_setting( 'affiliate_links_created' );
163 $is_hostinger_admin_page = $this->helper->is_hostinger_admin_page();
164 $is_client_eligible = $this->is_client_eligible();
165
166 if ( ! $is_hostinger_admin_page || empty( $this->get_survey_questions() ) ) {
167 return false;
168 }
169
170 return $not_submitted && $not_completed && $affiliate_links_exsists && $is_client_eligible;
171 }
172
173 public function is_prebuild_website_survey_enabled(): bool {
174
175 if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
176 return false;
177 }
178
179 $not_submitted = ! get_transient( self::SUBMITTED_SURVEY_TRANSIENT );
180 $not_completed = ! $this->settings->get_setting( 'prebuild_website_survey_completed' );
181 $is_hostinger_admin_page = $this->helper->is_hostinger_admin_page();
182 $is_client_eligible = $this->is_client_eligible();
183 $astra_templates_active = $this->helper->is_plugin_active( 'astra-sites' );
184
185 if ( ! $is_hostinger_admin_page || empty( $this->get_survey_questions() ) ) {
186 return false;
187 }
188
189 return $not_submitted && $not_completed && $is_client_eligible && $astra_templates_active;
190 }
191
192 public function is_client_eligible(): bool {
193 $transient_request_key = self::IS_CLIENT_ELIGIBLE_TRANSIENT_REQUEST;
194 $transient_response_key = self::IS_CLIENT_ELIGIBLE_TRANSIENT_RESPONSE;
195 $cached_eligibility = get_transient( $transient_response_key );
196
197 // Check if a request is already in progress
198 if ( get_transient( 'hts_eligible_request' ) ) {
199 return false;
200 }
201
202 // Check if transient response exists
203 if ( $cached_eligibility && ( $cached_eligibility === 'eligible' || $cached_eligibility === 'not_eligible' ) ) {
204 return $cached_eligibility === 'eligible';
205 }
206
207 // Attempt to set transient request
208 if ( ! $this->helper->check_transient_eligibility( $transient_request_key, self::CACHE_THREE_HOURS ) ) {
209 return false;
210 }
211
212 try {
213 // Set transient flag to indicate request in progress
214 set_transient( 'hts_eligible_request', 'in_progress', 60 );
215
216 $is_eligible = $this->surveys_rest->is_client_eligible();
217
218 // Clear the request transient flag
219 delete_transient( 'hts_eligible_request' );
220
221 if ( has_action( 'litespeed_purge_all' ) ) {
222 do_action( 'litespeed_purge_all' );
223 }
224
225 if ( $is_eligible ) {
226 set_transient( $transient_response_key, 'eligible', self::CACHE_THREE_HOURS );
227 return $is_eligible;
228 }
229
230 set_transient( $transient_response_key, 'not_eligible', self::CACHE_THREE_HOURS );
231 return false;
232 } catch ( Exception $exception ) {
233 $this->helper->error_log( 'Error checking eligibility: ' . $exception->getMessage() );
234
235 return false;
236 }
237 }
238
239 public function get_survey_questions(): array {
240 $transient_request_key = self::SURVEY_QUESTIONS_TRANSIENT_REQUEST;
241 $transient_response_key = self::SURVEY_QUESTIONS_TRANSIENT_RESPONSE;
242
243 // Check if a request is already in progress
244 if ( get_transient( 'hts_questions_request' ) ) {
245 return array();
246 }
247
248 // Check if transient response exists
249 $cached_questions = get_transient( $transient_response_key );
250
251 if ( false !== $cached_questions ) {
252 return $cached_questions;
253 }
254
255 // Attempt to set transient request
256 if ( ! $this->helper->check_transient_eligibility( $transient_request_key, self::CACHE_THREE_HOURS ) ) {
257 return array();
258 }
259
260 try {
261 // Set transient flag to indicate request in progress
262 set_transient( 'hts_questions_request', 'in_progress', 60 );
263 $survey_questions = $this->surveys_rest->get_survey_questions();
264
265 // Clear the request transient flag
266 delete_transient( 'hts_questions_request' );
267
268 set_transient( $transient_response_key, $survey_questions, self::CACHE_THREE_HOURS );
269
270 return $survey_questions;
271 } catch ( Exception $exception ) {
272 $this->helper->error_log( 'Error getting survey questions: ' . $exception->getMessage() );
273
274 return array();
275 }
276 }
277
278 public function submit_survey_answers( array $answers, string $survey_type ): void {
279 $required_survey_items = $this->get_required_survey_items( $survey_type );
280 $data = array(
281 'identifier' => self::CLIENT_SURVEY_IDENTIFIER,
282 'answers' => $required_survey_items,
283 );
284
285 $answers = $this->add_user_answers( $data, $answers );
286 $success = $this->surveys_rest->submit_survey_data( $answers, $survey_type );
287
288 set_transient( self::SUBMITTED_SURVEY_TRANSIENT, true, self::TIME_24_HOURS );
289
290 if ( $success ) {
291 delete_transient( self::IS_CLIENT_ELIGIBLE_TRANSIENT_RESPONSE );
292
293 switch ( $survey_type ) {
294 case 'woo_survey':
295 $setting_key = 'woocommerce_survey_completed';
296 break;
297
298 case 'ai_onboarding_survey':
299 $setting_key = 'ai_onboarding_survey_completed';
300 break;
301
302 case 'prebuild_website_survey':
303 $setting_key = 'prebuild_website_survey_completed';
304 break;
305
306 case 'affiliate_plugin_survey':
307 $setting_key = 'affiliate_survey_completed';
308 break;
309
310 default:
311 $setting_key = 'feedback_survey_completed';
312 }
313
314 $this->settings->update_setting( $setting_key, true );
315 wp_send_json( __( 'Survey completed', 'hostinger' ) );
316
317 if ( has_action( 'litespeed_purge_all' ) ) {
318 do_action( 'litespeed_purge_all' );
319 }
320 }
321 }
322
323 public function get_wp_survey_questions(): array {
324 $all_questions = $this->get_survey_questions();
325 $question_slugs = array( 'score', 'comment' );
326
327 return $this->filter_questions_by_slug( $all_questions, $question_slugs );
328 }
329
330 public function get_specified_survey_questions( array $survey_questions, string $survey_type = 'ai_survey' ): array {
331 $specified_survey_questions = array(
332 'pages' => array(),
333 'showQuestionNumbers' => 'off',
334 'showTOC' => false,
335 'pageNextText' => __( 'Next', 'hostinger' ),
336 'pagePrevText' => __( 'Previous', 'hostinger' ),
337 'completeText' => __( 'Submit', 'hostinger' ),
338 'completedHtml' => __( 'Thank you for completing the survey !', 'hostinger' ),
339 'requiredText' => '*',
340 );
341
342 foreach ( $survey_questions as $question ) {
343 $title = '';
344 switch ( $survey_type ) {
345 case 'woo_survey':
346 $title = $this->survey_questions->map_survey_questions( $question['slug'] )['woo_question'];
347 break;
348
349 case 'prebuild_website_survey':
350 $title = $this->survey_questions->map_survey_questions( $question['slug'] )['prebuild_website_question'];
351 break;
352
353 case 'ai_onboarding_survey':
354 $title = $this->survey_questions->map_survey_questions( $question['slug'] )['ai_question'];
355 break;
356
357 case 'affiliate_plugin_survey':
358 $title = $this->survey_questions->map_survey_questions( $question['slug'] )['affiliate_question'];
359 break;
360
361 default:
362 $title = $this->survey_questions->map_survey_questions( $question['slug'] )['question'];
363 break;
364 }
365
366 $element = array(
367 'type' => $this->survey_questions->map_survey_questions( $question['slug'] )['type'],
368 'name' => $question['slug'],
369 'title' => $title,
370 'requiredErrorText' => __( 'Response required.', 'hostinger' ),
371 );
372
373 if ( $question['slug'] == 'comment' ) {
374 $element['maxLength'] = 250;
375 }
376
377 if ( isset( $question['rules'] ) ) {
378 $between_rule = $this->get_between_rule_values( $question['rules'] );
379 if ( $between_rule ) {
380 $element['rateMin'] = $between_rule[0];
381 $element['rateMax'] = $between_rule[1];
382 $element['minRateDescription'] = __( 'Poor', 'hostinger' );
383 $element['maxRateDescription'] = __( 'Excellent', 'hostinger' );
384 }
385
386 if ( $this->is_survey_question_required( $question ) ) {
387 $element['isRequired'] = true;
388 }
389 }
390
391 $question_data = array(
392 'name' => $question['slug'],
393 'elements' => array( $element ),
394 );
395
396 $specified_survey_questions['pages'][] = $question_data;
397 }
398
399 return $specified_survey_questions;
400 }
401
402 public function get_between_rule_values( array $rules ): array {
403 foreach ( $rules as $rule ) {
404 $position = strpos( $rule, 'between:' );
405 if ( $position !== false ) {
406 $between_values = $this->extract_between_values( $rule, $position );
407 if ( count( $between_values ) === 2 ) {
408 return $between_values;
409 }
410 }
411 }
412
413 return array();
414 }
415
416 public function generate_survey_html( string $survey_class ): string {
417 ob_start();
418 ?>
419 <div class="hts-survey-wrapper <?php echo esc_attr( $survey_class ); ?>">
420 <div class="close-btn">
421 <svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="100" height="100" viewBox="0 0 24 24">
422 <path d="M 4.9902344 3.9902344 A 1.0001 1.0001 0 0 0 4.2929688 5.7070312 L 10.585938 12 L 4.2929688 18.292969 A 1.0001 1.0001 0 1 0 5.7070312 19.707031 L 12 13.414062 L 18.292969 19.707031 A 1.0001 1.0001 0 1 0 19.707031 18.292969 L 13.414062 12 L 19.707031 5.7070312 A 1.0001 1.0001 0 0 0 18.980469 3.9902344 A 1.0001 1.0001 0 0 0 18.292969 4.2929688 L 12 10.585938 L 5.7070312 4.2929688 A 1.0001 1.0001 0 0 0 4.9902344 3.9902344 z"></path>
423 </svg>
424 </div>
425 <div id="hostinger-feedback-survey"></div>
426 <div id="hts-questionsLeft">
427 <span id="hts-currentQuestion">1</span>
428 <?php
429 echo esc_html(
430 __(
431 'Question',
432 'hostinger'
433 )
434 );
435 ?>
436 <?php echo esc_html( __( 'of ', 'hostinger' ) ); ?>
437 <span id="hts-allQuestions"></span>
438 </div>
439 </div>
440 <?php
441 return ob_get_clean();
442 }
443
444 public function customer_csat_survey(): void {
445 if ( ! did_action( 'customer_csat_survey' ) ) {
446 $survey_html = $this->generate_survey_html( 'hts-woocommerce-csat' );
447 echo $survey_html;
448 do_action( 'customer_csat_survey' );
449 }
450 }
451
452 public function customer_ai_csat_survey(): void {
453 if ( ! did_action( 'customer_ai_csat_survey' ) ) {
454 $survey_html = $this->generate_survey_html( 'hts-ai-onboarding-csat' );
455 echo $survey_html;
456 do_action( 'customer_ai_csat_survey' );
457 }
458 }
459
460 public function ai_plugin_survey(): void {
461 if ( ! did_action( 'ai_plugin_survey' ) ) {
462 $survey_html = $this->generate_survey_html( '' );
463 echo $survey_html;
464 do_action( 'ai_plugin_survey' );
465 }
466 }
467
468 public function affiliate_plugin_survey(): void {
469 if ( ! did_action( 'affiliate_plugin_survey' ) ) {
470 $survey_html = $this->generate_survey_html( 'hts-affiliate-csat' );
471 echo $survey_html;
472 do_action( 'affiliate_plugin_survey' );
473 }
474 }
475
476 public function prebuild_website_survey(): void {
477 if ( ! did_action( 'prebuild_website_plugin_survey' ) ) {
478 $survey_html = $this->generate_survey_html( 'hts-prebuild-website-csat' );
479 echo $survey_html;
480 do_action( 'prebuild_website_plugin_survey' );
481 }
482 }
483
484 private function extract_between_values( string $rule, int $position ): array {
485 $between_prefix_length = strlen( 'between:' );
486 $between_values = explode( ',', substr( $rule, $position + $between_prefix_length ) );
487
488 return count( $between_values ) === 2 ? $between_values : array();
489 }
490
491 public function is_time_elapsed( string $first_login_at, int $time_in_seconds ): bool {
492 $current_time = time();
493 $time_elapsed = $current_time - $time_in_seconds;
494
495 return $time_elapsed >= $first_login_at;
496 }
497
498 private function get_required_survey_items( string $survey_type ): array {
499 switch ( $survey_type ) {
500 case 'woo_survey':
501 return array(
502 array(
503 'question_slug' => self::LOCATION_SLUG,
504 'answer' => self::WOO_SURVEY_IDENTIFIER,
505 ),
506 );
507 case 'ai_onboarding_survey':
508 return array(
509 array(
510 'question_slug' => self::LOCATION_SLUG,
511 'answer' => self::AI_ONBOARDING_SURVEY_IDENTIFIER,
512 ),
513 );
514 case 'affiliate_plugin_survey':
515 return array(
516 array(
517 'question_slug' => self::LOCATION_SLUG,
518 'answer' => self::AFFILIATE_SURVEY_IDENTIFIER,
519 ),
520 );
521 case 'prebuild_website_survey':
522 return array(
523 array(
524 'question_slug' => self::LOCATION_SLUG,
525 'answer' => self::PREBUILD_WEBSITE_SURVEY_IDENTIFIER,
526 ),
527 );
528 default:
529 return array(
530 array(
531 'question_slug' => self::LOCATION_SLUG,
532 'answer' => 'wordpress_ai_plugin',
533 ),
534 );
535 }
536 }
537
538 private function add_user_answers( array $data, array $answers ): array {
539 foreach ( $answers as $answer_slug => $answer ) {
540 $data['answers'][] = array(
541 'question_slug' => $answer_slug,
542 'answer' => $answer,
543 );
544 }
545
546 return $data;
547 }
548
549 private function filter_questions_by_slug( array $all_questions, array $question_slugs ): array {
550 $questions_with_required_rule = array();
551
552 foreach ( $all_questions as $question ) {
553 if ( isset( $question['slug'] ) && in_array( $question['slug'], $question_slugs ) ) {
554 $questions_with_required_rule[] = array(
555 'slug' => $question['slug'],
556 'rules' => $question['rules'],
557 );
558 }
559 }
560
561 return $questions_with_required_rule;
562 }
563
564 private function is_survey_question_required( array $question ): bool {
565 return isset( $question['rules'] ) && in_array( 'required', $question['rules'] );
566 }
567
568 public function get_oldest_product_date(): int {
569 global $wpdb;
570
571 $get_product_date = $wpdb->prepare(
572 "
573 SELECT MIN(post_date)
574 FROM {$wpdb->posts}
575 WHERE post_type = %s
576 AND post_status = %s
577 ",
578 'product',
579 'publish'
580 );
581
582 $oldest_product_date = $wpdb->get_var( $get_product_date );
583
584 if ( $oldest_product_date !== null ) {
585 $oldest_product_date_timestamp = strtotime( $oldest_product_date );
586
587 if ( $oldest_product_date_timestamp !== false ) {
588 return $oldest_product_date_timestamp;
589 }
590 }
591
592 return strtotime( '-1 year' );
593 }
594 }
595