admin
1 year ago
models
1 year ago
query-views
1 year ago
rest-endpoints
1 year ago
tab-handlers
1 year ago
module.php
1 year ago
tools.php
1 year ago
user-journey-rest-controller.php
1 year ago
module.php
665 lines
| 1 | <?php |
| 2 | namespace JFB_Modules\User_Journey; |
| 3 | |
| 4 | use Jet_Form_Builder\Admin\Tabs_Handlers\Tab_Handler_Manager; |
| 5 | use JFB_Components\Module\Base_Module_After_Install_It; |
| 6 | use JFB_Components\Module\Base_Module_Dir_It; |
| 7 | use JFB_Components\Module\Base_Module_Dir_Trait; |
| 8 | use JFB_Components\Module\Base_Module_Handle_It; |
| 9 | use JFB_Components\Module\Base_Module_Handle_Trait; |
| 10 | use JFB_Components\Module\Base_Module_It; |
| 11 | use JFB_Components\Module\Base_Module_Static_Instance_It; |
| 12 | use JFB_Components\Module\Base_Module_Static_Instance_Trait; |
| 13 | use JFB_Components\Module\Base_Module_Url_It; |
| 14 | use JFB_Components\Module\Base_Module_Url_Trait; |
| 15 | use JFB_Modules\User_Journey\Admin\Meta_Boxes\Form_Record_User_Journey_Box; |
| 16 | use JFB_Modules\User_Journey\Models\User_Journey_Model; |
| 17 | use Jet_Form_Builder\Db_Queries\Exceptions\Sql_Exception; |
| 18 | use JFB_Modules\User_Journey\User_Journey_Rest_Controller; |
| 19 | |
| 20 | // If this file is called directly, abort. |
| 21 | if ( ! defined( 'WPINC' ) ) { |
| 22 | die; |
| 23 | } |
| 24 | |
| 25 | /** |
| 26 | * @method static Module instance() |
| 27 | * |
| 28 | * @package JFB_Modules\User_Journey |
| 29 | */ |
| 30 | class Module implements |
| 31 | Base_Module_Dir_It, |
| 32 | Base_Module_It, |
| 33 | Base_Module_Handle_It, |
| 34 | Base_Module_Url_It, |
| 35 | Base_Module_After_Install_It, |
| 36 | Base_Module_Static_Instance_It { |
| 37 | |
| 38 | use Base_Module_Handle_Trait; |
| 39 | use Base_Module_Dir_Trait; |
| 40 | use Base_Module_Url_Trait; |
| 41 | use Base_Module_Static_Instance_Trait; |
| 42 | |
| 43 | private $rest; |
| 44 | private $forms; |
| 45 | /** |
| 46 | * Returns the instance ID for the module. |
| 47 | * |
| 48 | * @return string The instance ID. |
| 49 | */ |
| 50 | public static function get_instance_id(): string { |
| 51 | return 'user-journey'; |
| 52 | } |
| 53 | |
| 54 | /** |
| 55 | * Checks if the form-record module is available. |
| 56 | * |
| 57 | * @return bool True if the module is available, false otherwise. |
| 58 | */ |
| 59 | public function condition(): bool { |
| 60 | return jet_form_builder()->has_module( 'form-record' ); |
| 61 | } |
| 62 | |
| 63 | /** |
| 64 | * Initializes hooks for the module. |
| 65 | */ |
| 66 | public function init_hooks() { |
| 67 | add_action( |
| 68 | 'rest_api_init', |
| 69 | array( $this->get_rest(), 'register_routes' ) |
| 70 | ); |
| 71 | |
| 72 | add_filter( |
| 73 | 'jet-form-builder/page-containers/jfb-records-single', |
| 74 | array( $this, 'add_box_to_single_record' ), |
| 75 | 0 |
| 76 | ); |
| 77 | |
| 78 | if ( $this->is_user_journey_enabled() ) { |
| 79 | |
| 80 | add_action( |
| 81 | 'jet-form-builder/form-handler/before-send', |
| 82 | array( $this, 'add_query_args' ), |
| 83 | 10 |
| 84 | ); |
| 85 | |
| 86 | add_filter( |
| 87 | 'jet-form-builder/actions/redirect-to-page/redirect-args', |
| 88 | array( $this, 'add_redirect_to_page_action_query_args' ), |
| 89 | 10, |
| 90 | 2 |
| 91 | ); |
| 92 | |
| 93 | add_filter( |
| 94 | 'jet-fb/response-handler/query-args', |
| 95 | array( $this, 'add_gateway_query_args' ), |
| 96 | 10, |
| 97 | 2 |
| 98 | ); |
| 99 | |
| 100 | add_action( |
| 101 | 'wp_footer', |
| 102 | array( $this, 'enqueue_journey_script' ) |
| 103 | ); |
| 104 | |
| 105 | add_filter( |
| 106 | 'jet-form-builder/editor/config', |
| 107 | array( $this, 'add_user_journey_settings' ), |
| 108 | 10, |
| 109 | 1 |
| 110 | ); |
| 111 | |
| 112 | add_action( |
| 113 | 'jet-form-builder/form-record/save-record-action', |
| 114 | array( $this, 'save_user_journey' ), |
| 115 | 10, |
| 116 | 2 |
| 117 | ); |
| 118 | |
| 119 | add_action( |
| 120 | 'wp_head', |
| 121 | array( $this, 'clear_journey_data_on_reload' ), |
| 122 | -9999, |
| 123 | 2 |
| 124 | ); |
| 125 | } |
| 126 | } |
| 127 | |
| 128 | /** |
| 129 | * Removes hooks for the module. |
| 130 | */ |
| 131 | public function remove_hooks() { |
| 132 | remove_action( |
| 133 | 'rest_api_init', |
| 134 | array( $this->get_rest(), 'register_routes' ) |
| 135 | ); |
| 136 | |
| 137 | remove_filter( |
| 138 | 'jet-form-builder/page-containers/jfb-records-single', |
| 139 | array( $this, 'add_box_to_single_record' ), |
| 140 | 0 |
| 141 | ); |
| 142 | |
| 143 | if ( $this->is_user_journey_enabled() ) { |
| 144 | remove_action( |
| 145 | 'wp_footer', |
| 146 | array( $this, 'enqueue_journey_script' ) |
| 147 | ); |
| 148 | |
| 149 | remove_filter( |
| 150 | 'jet-form-builder/editor/config', |
| 151 | array( $this, 'add_user_journey_settings' ) |
| 152 | ); |
| 153 | |
| 154 | remove_action( |
| 155 | 'jet-form-builder/form-record/save-record-action', |
| 156 | array( $this, 'save_user_journey' ) |
| 157 | ); |
| 158 | |
| 159 | remove_action( |
| 160 | 'wp_head', |
| 161 | array( $this, 'clear_journey_data_on_reload' ) |
| 162 | ); |
| 163 | |
| 164 | remove_filter( |
| 165 | 'jet-form-builder/actions/redirect-to-page/redirect-args', |
| 166 | array( $this, 'add_redirect_to_page_action_query_args' ) |
| 167 | ); |
| 168 | |
| 169 | remove_action( |
| 170 | 'jet-form-builder/form-handler/before-send', |
| 171 | array( $this, 'add_query_args' ) |
| 172 | ); |
| 173 | } |
| 174 | } |
| 175 | |
| 176 | /** |
| 177 | * Handles actions to perform on module installation. |
| 178 | */ |
| 179 | public function on_install() { |
| 180 | $this->rest = new User_Journey_Rest_Controller(); |
| 181 | $this->set_forms(); |
| 182 | |
| 183 | Tab_Handler_Manager::instance()->install( new Tab_Handlers\User_Journey_Handler() ); |
| 184 | } |
| 185 | |
| 186 | /** |
| 187 | * Handles actions to perform on module uninstallation. |
| 188 | */ |
| 189 | public function on_uninstall() { |
| 190 | Tab_Handler_Manager::instance()->uninstall( new Tab_Handlers\User_Journey_Handler() ); |
| 191 | } |
| 192 | |
| 193 | public function set_forms() { |
| 194 | if ( ! \JFB_Modules\Post_Type\Module::class ) { |
| 195 | return array(); |
| 196 | } |
| 197 | |
| 198 | $this->forms = get_posts( |
| 199 | array( |
| 200 | 'post_type' => \JFB_Modules\Post_Type\Module::SLUG, |
| 201 | 'posts_per_page' => -1, |
| 202 | ) |
| 203 | ); |
| 204 | } |
| 205 | |
| 206 | public function get_forms() { |
| 207 | return $this->forms; |
| 208 | } |
| 209 | |
| 210 | public function add_gateway_query_args( $args, $response ) { |
| 211 | if ( ! \JFB_Modules\Post_Type\Module::class ) { |
| 212 | return $args; |
| 213 | } |
| 214 | |
| 215 | if ( isset( $response->args['form_id'] ) && isset( $response->args['status'] ) ) { |
| 216 | if ( false === strpos( $args['status'], '%7C' ) && false === strpos( $args['status'], '|' ) ) { |
| 217 | return $args; |
| 218 | } else if ( false !== strpos( $args['status'], '%7C' ) ) { |
| 219 | $status = explode( '%7C', $args['status'] )[0]; |
| 220 | } else { |
| 221 | $status = explode( '|', $args['status'] )[0]; |
| 222 | } |
| 223 | |
| 224 | $jet_fb_user_journey_settings = $this->get_journey_settings(); |
| 225 | |
| 226 | if ( 'success' === $jet_fb_user_journey_settings['clear_after_submit'] ) { |
| 227 | if ( 'dsuccess' === $status ) { |
| 228 | $args['jfb_clear_journey'] = $response->args['form_id']; |
| 229 | } |
| 230 | } else if ( 'always' === $jet_fb_user_journey_settings['clear_after_submit'] ) { |
| 231 | $args['jfb_clear_journey'] = $response->args['form_id']; |
| 232 | } |
| 233 | } |
| 234 | |
| 235 | return $args; |
| 236 | } |
| 237 | |
| 238 | public function add_redirect_to_page_action_query_args( $args, $handler ) { |
| 239 | if ( ! \JFB_Modules\Post_Type\Module::class ) { |
| 240 | return $args; |
| 241 | } |
| 242 | |
| 243 | $post_type_module = \Jet_Form_Builder\Plugin::instance()->module( \JFB_Modules\Post_Type\Module::class ); |
| 244 | $journey_form_ids = $this->get_form_ids_with_save_user_journey(); |
| 245 | |
| 246 | $forms = $this->get_forms(); |
| 247 | |
| 248 | foreach ( $forms as $form ) { |
| 249 | $actions = $post_type_module->get_actions( $form->ID ); |
| 250 | foreach ( $actions as $action ) { |
| 251 | if ( ( $action['type'] ?? '' ) === 'redirect_to_page' ) { |
| 252 | if ( isset( $handler->_id ) ) { |
| 253 | if ( in_array( $form->ID, $journey_form_ids ) && $action['id'] === $handler->_id ) { |
| 254 | $args['jfb_clear_journey'] = $form->ID; |
| 255 | } |
| 256 | } |
| 257 | break; |
| 258 | } |
| 259 | } |
| 260 | } |
| 261 | |
| 262 | return $args; |
| 263 | } |
| 264 | |
| 265 | public function get_form_ids_with_save_user_journey() { |
| 266 | $post_type_module = \Jet_Form_Builder\Plugin::instance()->module( \JFB_Modules\Post_Type\Module::class ); |
| 267 | $matched_form_ids = array(); |
| 268 | |
| 269 | $forms = $this->get_forms(); |
| 270 | |
| 271 | foreach ( $forms as $form ) { |
| 272 | $actions = $post_type_module->get_actions( $form->ID ); |
| 273 | |
| 274 | foreach ( $actions as $action ) { |
| 275 | if ( ( $action['type'] ?? '' ) === 'save_record' ) { |
| 276 | $save_user_journey = $action['settings']['save_record']['save_user_journey'] ?? false; |
| 277 | |
| 278 | if ( $save_user_journey && true === $save_user_journey ) { |
| 279 | $matched_form_ids[] = $form->ID; |
| 280 | } |
| 281 | } |
| 282 | } |
| 283 | } |
| 284 | |
| 285 | return $matched_form_ids; |
| 286 | } |
| 287 | |
| 288 | public function add_query_args( $instance ) { |
| 289 | $form_id = $instance->form_id; |
| 290 | |
| 291 | $instance->add_response_data( array( 'jfb_clear_journey' => $form_id ) ); |
| 292 | } |
| 293 | |
| 294 | /** |
| 295 | * Adds user journey settings to the provided settings array. |
| 296 | * |
| 297 | * @param array $settings The settings array to modify. |
| 298 | * |
| 299 | * @return array The modified settings array. |
| 300 | */ |
| 301 | public function add_user_journey_settings( $settings ) { |
| 302 | $user_journey_settings = Tab_Handler_Manager::get_options( 'user-journey-tab' ); |
| 303 | |
| 304 | $settings['user_journey'] = array( |
| 305 | 'enabled' => $user_journey_settings['enable_user_journey'] ?? false, |
| 306 | 'storage_type' => $user_journey_settings['storage_type'] ?? 'local', |
| 307 | 'clear_after_submit' => $user_journey_settings['clear_after_submit'] ?? 'success', |
| 308 | ); |
| 309 | |
| 310 | return $settings; |
| 311 | } |
| 312 | |
| 313 | /** |
| 314 | * Adds a meta box to a single record. |
| 315 | * |
| 316 | * @param Base_Meta_Container[] $containers The array of meta containers. |
| 317 | * |
| 318 | * @return array The modified array of meta containers. |
| 319 | */ |
| 320 | public function add_box_to_single_record( array $containers ): array { |
| 321 | $containers[0]->add_meta_box( new Form_Record_User_Journey_Box() ); |
| 322 | |
| 323 | return $containers; |
| 324 | } |
| 325 | |
| 326 | /** |
| 327 | * Checks if user journey tracking is enabled in the settings. |
| 328 | * |
| 329 | * @return bool True if user journey tracking is enabled, false otherwise. |
| 330 | */ |
| 331 | public function is_user_journey_enabled() { |
| 332 | $options = Tab_Handler_Manager::get_options( 'user-journey-tab' ); |
| 333 | return ! empty( $options['enable_user_journey'] ); |
| 334 | } |
| 335 | |
| 336 | /** |
| 337 | * Returns the journey tracking settings. |
| 338 | * |
| 339 | * @return array The journey settings. |
| 340 | */ |
| 341 | public function get_journey_settings() { |
| 342 | $options = Tab_Handler_Manager::get_options( 'user-journey-tab' ); |
| 343 | return array( |
| 344 | 'enabled' => ! empty( $options['enable_user_journey'] ), |
| 345 | 'storage_type' => $options['storage_type'] ?? 'local', |
| 346 | 'clear_after_submit' => $options['clear_after_submit'] ?? 'success', |
| 347 | 'form_ids_with_save_user_journey' => $this->get_form_ids_with_save_user_journey(), |
| 348 | ); |
| 349 | } |
| 350 | |
| 351 | public function clear_journey_data_on_reload() { |
| 352 | $jet_fb_user_journey_settings = $this->get_journey_settings(); |
| 353 | ?> |
| 354 | <script> |
| 355 | ( function() { |
| 356 | const settings = <?php echo wp_json_encode( $jet_fb_user_journey_settings ); ?>; |
| 357 | const storageKey = 'jet_fb_user_journey'; |
| 358 | const storage = settings.storage_type === 'local' ? localStorage : sessionStorage; |
| 359 | |
| 360 | var params = new URLSearchParams( window.location.search ); |
| 361 | |
| 362 | if ( params.has('jfb_clear_journey') ) { |
| 363 | var status = params.get('status') ?? 'unknown', |
| 364 | formId = params.get('jfb_clear_journey'); |
| 365 | |
| 366 | if ( status.includes('|') ) { |
| 367 | status = status.split('|')[0]; |
| 368 | } |
| 369 | |
| 370 | params.delete('jfb_clear_journey'); |
| 371 | |
| 372 | var newSearch = params.toString(); |
| 373 | |
| 374 | var newUrl = window.location.origin |
| 375 | + window.location.pathname |
| 376 | + ( newSearch ? '?' + newSearch : '' ) |
| 377 | + window.location.hash; |
| 378 | |
| 379 | window.history.replaceState( null, document.title, newUrl ); |
| 380 | |
| 381 | if ( ( 'success' === settings.clear_after_submit && ( 'success' === status || 'dsuccess' === status ) ) |
| 382 | || 'always' === settings.clear_after_submit || 'unknown' === status ) |
| 383 | { |
| 384 | const raw = storage.getItem( storageKey ); |
| 385 | |
| 386 | if ( ! raw ) { |
| 387 | return; |
| 388 | } |
| 389 | |
| 390 | let data = JSON.parse( raw ); |
| 391 | |
| 392 | if ( ! Array.isArray( data ) && data.hasOwnProperty( formId ) ) { |
| 393 | delete data[ formId ]; |
| 394 | } |
| 395 | |
| 396 | storage.setItem( storageKey, JSON.stringify( data ) ); |
| 397 | } |
| 398 | } |
| 399 | } )(); |
| 400 | </script> |
| 401 | <?php |
| 402 | } |
| 403 | |
| 404 | /** |
| 405 | * Enqueues JavaScript for tracking the user journey. |
| 406 | */ |
| 407 | public function enqueue_journey_script() { |
| 408 | $jet_fb_user_journey_settings = $this->get_journey_settings(); |
| 409 | ?> |
| 410 | <script> |
| 411 | ( function() { |
| 412 | const settings = <?php echo wp_json_encode( $jet_fb_user_journey_settings ); ?>; |
| 413 | const storageKey = 'jet_fb_user_journey'; |
| 414 | const storage = settings.storage_type === 'local' ? localStorage : sessionStorage; |
| 415 | const currentUrl = window.location.pathname; |
| 416 | const queryString = decodeURIComponent( window.location.search ); |
| 417 | const formIds = new Set( ( settings.form_ids_with_save_user_journey || [] ).map( Number ) ); |
| 418 | |
| 419 | let journeys; |
| 420 | |
| 421 | try { |
| 422 | journeys = JSON.parse( storage.getItem( storageKey ) ) || {}; |
| 423 | } catch { |
| 424 | journeys = {}; |
| 425 | } |
| 426 | |
| 427 | Object.keys( journeys ).forEach( id => { |
| 428 | if ( ! formIds.has( +id ) ) delete journeys[ id ]; |
| 429 | } ); |
| 430 | |
| 431 | const pageEntry = { url: currentUrl, query: queryString, timestamp: Date.now() }; |
| 432 | |
| 433 | function addJourney( journeys, formIds, to_form_id = null ) { |
| 434 | |
| 435 | if ( null !== to_form_id ) { |
| 436 | journeys[ to_form_id ] = []; |
| 437 | journeys[ to_form_id ].push( pageEntry ); |
| 438 | } else { |
| 439 | formIds.forEach( formId => { |
| 440 | if ( ! journeys[ formId ] ) { |
| 441 | journeys[ formId ] = []; |
| 442 | } |
| 443 | |
| 444 | const journey = journeys[ formId ]; |
| 445 | const lastEntry = 0 < journey.length ? journey[ journey.length - 1 ] : false; |
| 446 | |
| 447 | if ( ! lastEntry ) { |
| 448 | journey.push( pageEntry ); |
| 449 | } else if ( currentUrl !== lastEntry.url || queryString !== lastEntry.query ) { |
| 450 | journey.push( pageEntry ); |
| 451 | } |
| 452 | } ); |
| 453 | } |
| 454 | |
| 455 | storage.setItem( storageKey, JSON.stringify( journeys ) ); |
| 456 | } |
| 457 | |
| 458 | function clearJourney( form, on_success = true ) { |
| 459 | const formElement = form instanceof jQuery ? form[0] : form; |
| 460 | const formId = formElement.dataset.formId; |
| 461 | |
| 462 | let can_clear = false; |
| 463 | |
| 464 | if ( on_success ) { |
| 465 | if ( 'success' === settings.clear_after_submit || 'always' === settings.clear_after_submit ) { |
| 466 | can_clear = true; |
| 467 | } |
| 468 | } else { |
| 469 | if ( 'always' === settings.clear_after_submit ) { |
| 470 | can_clear = true; |
| 471 | } |
| 472 | } |
| 473 | |
| 474 | if ( formElement ) { |
| 475 | if ( formIds.has( +formId ) ) { |
| 476 | |
| 477 | if ( can_clear ) { |
| 478 | const raw = storage.getItem( storageKey ); |
| 479 | |
| 480 | if ( ! raw ) { |
| 481 | return; |
| 482 | } |
| 483 | |
| 484 | let data = JSON.parse( raw ); |
| 485 | |
| 486 | if ( ! Array.isArray( data ) && data.hasOwnProperty( formId ) ) { |
| 487 | delete data[ formId ]; |
| 488 | } |
| 489 | |
| 490 | storage.setItem( storageKey, JSON.stringify( data ) ); |
| 491 | |
| 492 | const savedJourneys = storage.getItem( storageKey ); |
| 493 | |
| 494 | if ( savedJourneys ) { |
| 495 | journeys = JSON.parse( savedJourneys ); |
| 496 | } |
| 497 | |
| 498 | addJourney( journeys, formIds, formId ); |
| 499 | |
| 500 | if ( window?.JetFormBuilderSettings?.devmode ) { |
| 501 | /* eslint-disable no-console */ |
| 502 | console.group( 'User Journeys' ); |
| 503 | console.info( journeys ); |
| 504 | console.groupEnd(); |
| 505 | /* eslint-enable no-console */ |
| 506 | } |
| 507 | } |
| 508 | } |
| 509 | } else { |
| 510 | console.error('Form element is not defined or not a valid DOM element.'); |
| 511 | } |
| 512 | } |
| 513 | |
| 514 | addJourney( journeys, formIds ); |
| 515 | |
| 516 | jQuery( document ).ready( function() { |
| 517 | if ( window?.JetFormBuilderSettings?.devmode ) { |
| 518 | /* eslint-disable no-console */ |
| 519 | console.group( 'User Journeys' ); |
| 520 | console.info( journeys ); |
| 521 | console.groupEnd(); |
| 522 | /* eslint-enable no-console */ |
| 523 | } |
| 524 | |
| 525 | JetPlugins.hooks.addFilter( |
| 526 | 'jet.fb.submit.ajax.promises', |
| 527 | 'user_journey_promise', |
| 528 | function ( promises, $form ) { |
| 529 | promises.push( new Promise( ( resolve, reject ) => { |
| 530 | const formElement = $form instanceof jQuery ? $form[0] : $form; |
| 531 | const formId = formElement.dataset.formId; |
| 532 | const userJourneyData = storage.getItem( storageKey ); |
| 533 | const userJourneyDataParsed = JSON.parse(userJourneyData || '{}'); |
| 534 | const formSpecificData = userJourneyDataParsed[formId] || ''; |
| 535 | |
| 536 | if ( formElement ) { |
| 537 | if ( formIds.has( +formId ) ) { |
| 538 | if ( userJourneyData ) { |
| 539 | let hiddenInput = $form[0].querySelector( 'input[name="_user_journey"]' ); |
| 540 | |
| 541 | if ( !hiddenInput ) { |
| 542 | hiddenInput = document.createElement( 'input' ); |
| 543 | |
| 544 | hiddenInput.type = 'hidden'; |
| 545 | hiddenInput.name = '_user_journey'; |
| 546 | |
| 547 | $form[0].appendChild( hiddenInput ); |
| 548 | } |
| 549 | hiddenInput.value = JSON.stringify( formSpecificData ); |
| 550 | } |
| 551 | } |
| 552 | } |
| 553 | |
| 554 | resolve(); |
| 555 | } ) ); |
| 556 | |
| 557 | return promises; |
| 558 | } |
| 559 | ); |
| 560 | |
| 561 | JetPlugins.hooks.addFilter( |
| 562 | 'jet.fb.submit.reload.promises', |
| 563 | 'user_journey_promise', |
| 564 | function( $promises, $context ) { |
| 565 | $promises.push( |
| 566 | new Promise( ( resolve ) => { |
| 567 | const rootNode = $context.target; |
| 568 | const userJourneyData = storage.getItem( storageKey ); |
| 569 | const formId = rootNode.dataset.formId; |
| 570 | const userJourneyDataParsed = JSON.parse(userJourneyData || '{}'); |
| 571 | const formSpecificData = userJourneyDataParsed[formId] || ''; |
| 572 | |
| 573 | if ( formIds.has( +formId ) && userJourneyData ) { |
| 574 | let hiddenInput = rootNode.querySelector( 'input[name="_user_journey"]' ); |
| 575 | |
| 576 | if ( ! hiddenInput ) { |
| 577 | hiddenInput = document.createElement( 'input' ); |
| 578 | |
| 579 | hiddenInput.type = 'hidden'; |
| 580 | hiddenInput.name = '_user_journey'; |
| 581 | |
| 582 | rootNode.appendChild( hiddenInput ); |
| 583 | } |
| 584 | hiddenInput.value = JSON.stringify( formSpecificData ); |
| 585 | } |
| 586 | resolve(); |
| 587 | } ) |
| 588 | ); |
| 589 | |
| 590 | return $promises; |
| 591 | } |
| 592 | ); |
| 593 | |
| 594 | jQuery( document ).on('jet-form-builder/ajax/on-success', function( event, response, form ) { |
| 595 | clearJourney( form ); |
| 596 | } ); |
| 597 | |
| 598 | jQuery( document ).on('jet-form-builder/ajax/processing-error', function( event, response, form ) { |
| 599 | clearJourney( form, false ); |
| 600 | } ); |
| 601 | |
| 602 | jQuery( document ).on('jet-form-builder/ajax/on-fail', function( event, jqXHR, textStatus, errorThrown, form ) { |
| 603 | clearJourney( form, false ); |
| 604 | } ); |
| 605 | } ); |
| 606 | |
| 607 | } )(); |
| 608 | </script> |
| 609 | <?php |
| 610 | } |
| 611 | |
| 612 | /** |
| 613 | * Saves the user journey to the database after form submission. |
| 614 | * |
| 615 | * @param int $record_id The ID of the form record. |
| 616 | * @param array $action_request The action request data. |
| 617 | */ |
| 618 | public function save_user_journey( $record_id, $action_request ) { |
| 619 | try { |
| 620 | ( new User_Journey_Model() )->create(); |
| 621 | } catch ( Sql_Exception $e ) { |
| 622 | if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { |
| 623 | error_log( $e->getMessage() ); |
| 624 | } |
| 625 | } |
| 626 | |
| 627 | if ( ! $record_id ) { |
| 628 | return; |
| 629 | } |
| 630 | |
| 631 | // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.MissingUnslash |
| 632 | $user_journey = isset( $_POST['_user_journey'] ) ? sanitize_text_field( $_POST['_user_journey'] ) : null; |
| 633 | |
| 634 | if ( ! $user_journey ) { |
| 635 | return; |
| 636 | } |
| 637 | |
| 638 | $journey_data = json_decode( wp_unslash( $user_journey ), true ); |
| 639 | |
| 640 | if ( ! is_array( $journey_data ) ) { |
| 641 | return; |
| 642 | } |
| 643 | |
| 644 | foreach ( $journey_data as $step => $item ) { |
| 645 | $journey_results[] = array( |
| 646 | 'record_id' => $record_id, |
| 647 | 'journey_step' => $step, |
| 648 | 'journey_url' => sanitize_text_field( $item['url'] ), |
| 649 | 'journey_query' => urldecode( $item['query'] ?? '' ), |
| 650 | 'timestamp' => $item['timestamp'], |
| 651 | ); |
| 652 | } |
| 653 | |
| 654 | ( new User_Journey_Model() )->insert_many( $journey_results ); |
| 655 | } |
| 656 | |
| 657 | /** |
| 658 | * Returns the REST controller for the user journey. |
| 659 | * |
| 660 | * @return User_Journey_Rest_Controller The REST controller instance. |
| 661 | */ |
| 662 | public function get_rest(): User_Journey_Rest_Controller { |
| 663 | return $this->rest; |
| 664 | } |
| 665 | } |