PluginProbe
Lasso Lite – Affiliate Link Manager & Product Displays / 158
Lasso Lite – Affiliate Link Manager & Product Displays v158
158 157 155 156 154 153 152 151 150 149 148 trunk 0.9.9 104 105 106 107 108 109 110 111 112 113 114 115 All 57 releases
← All changes | pages/class-hook.php +749 -29 113158 View file →
@@ -9,13 +9,16 @@
9 9
10 10 use LassoLite\Admin\Constant;
11 11
12 12 use LassoLite\Classes\Amazon_Api;
13 +use LassoLite\Classes\Beacon_Proxy;
13 14 use LassoLite\Classes\Enum;
14 15 use LassoLite\Classes\Helper;
15 16 use LassoLite\Classes\Page;
16 17 use LassoLite\Classes\Setting;
17 18 use LassoLite\Classes\Shortcode;
19 +use LassoLite\Classes\License;
20 +use LassoLite\Classes\Realtime_Click;
18 21
19 22 /**
20 23 * Hook.
21 24 */
@@ -40,8 +43,11 @@
40 43 public function register_hooks() {
41 44 add_action( 'admin_init', array( $this, 'amazon_api_pre_populated_automatically' ) );
42 45 add_action( 'init', array( $this, 'register_taxonomy' ) );
43 46 add_action( 'admin_menu', array( $this, 'build_admin_menu' ), 2 );
47 + add_action( 'init', array( $this, 'lasso_register_connect_snippet_rewrite' ) );
48 + add_action( 'init', array( $this, 'maybe_flush_vanity_rewrites_on_upgrade' ), 20 );
49 + add_action( 'upgrader_process_complete', array( $this, 'lasso_connect_snippet_flush_on_upgrade' ), 10, 2 );
44 50
45 51 $lasso_shortcode = new Shortcode();
46 52 add_shortcode( 'lasso', array( $lasso_shortcode, 'lasso_lite_core_shortcode' ) );
47 53 add_filter( 'pre_do_shortcode_tag', array( $this, 'filter_pre_do_shortcode_lasso_lite' ), 10, 4 );
@@ -49,8 +55,9 @@
49 55 add_action( 'wp_head', array( $this, 'lasso_custom_css' ) ); // ? frontend
50 56 add_action( 'admin_head', array( $this, 'lasso_custom_css' ) ); // ? admin
51 57 add_action( 'admin_head', array( $this, 'lasso_custom_menu' ) ); // ? admin
52 58 add_action( 'wp_enqueue_scripts', array( $this, 'add_scripts_frontend' ) ); // ? frontend
59 + add_filter( 'body_class', array( $this, 'filter_body_class_lasso_lite_version' ) ); // ? frontend
53 60
54 61 add_action( 'admin_enqueue_scripts', array( $this, 'add_scripts' ) );
55 62 add_action( 'admin_enqueue_scripts', array( $this, 'add_styles' ) );
56 63
@@ -57,10 +64,14 @@
57 64 // ? re-order submenu pages
58 65 add_filter( 'custom_menu_order', array( $this, 'lasso_order_submenu' ) );
59 66
60 67 // ? lasso gutenberg block
68 + add_action( 'enqueue_block_assets', array( $this, 'lasso_block_editor_css_variables' ) );
61 69 add_action( 'enqueue_block_editor_assets', array( $this, 'lasso_lite_gutenberg_block' ) );
62 70
71 + // ? Elementor
72 + add_action( 'elementor/init', array( $this, 'elementor_init' ) );
73 +
63 74 // ? add Lasso button into TinyMCE
64 75 add_filter( 'mce_external_plugins', array( $this, 'lasso_add_tinymce_plugin' ) );
65 76 add_filter( 'mce_buttons', array( $this, 'lasso_lite_register_my_tc_button' ) );
66 77
@@ -70,11 +81,19 @@
70 81
71 82 add_filter( 'rest_pre_echo_response', array( $this, 'update_post_type_gutenberg' ), 200, 3 );
72 83
73 84 add_filter( 'wp_link_query', array( $this, 'update_post_type_classic_editor' ), 10, 1 );
74 - add_filter( 'admin_footer_text', array( $this, 'admin_footer' ), 100, 2 );
75 85 add_filter( 'update_footer', '__return_empty_string', 11 );
76 86
87 + // ? WP Rocket
88 + add_filter( 'rocket_exclude_js', array( $this, 'exclude_lasso_performance_js_from_rocket_cache' ) );
89 +
90 + add_filter( 'query_vars', array( $this, 'lasso_connect_snippet_query_var' ) );
91 +
92 + // Serve vanity JS path /js/snippet.min.js via plugin handler (run as early as possible)
93 + add_action( 'template_redirect', array( $this, 'serve_connect_snippet' ), 0 );
94 + add_action( 'template_redirect', array( $this, 'serve_beacon_proxy' ), 0 );
95 +
77 96 $setting = new Setting();
78 97 if ( $setting->is_surls_page() ) {
79 98 // ? plugin: Pretty Links Pro
80 99 if ( class_exists( 'PrliUpdateController' ) ) {
@@ -104,9 +123,9 @@
104 123 remove_action( 'init', array( $WooZone, 'initThePlugin' ), 5 ); // phpcs:ignore
105 124 }
106 125
107 126 // ? plugin: Client Portal
108 - $lasso_page = $_GET['page'] ?? ''; // phpcs:ignore
127 + $lasso_page = Helper::GET()['page'] ?? ''; // phpcs:ignore
109 128 if ( class_exists( 'CCGClientPortal' ) && Helper::add_prefix_page( Enum::PAGE_DASHBOARD ) === $lasso_page ) {
110 129 global $zohopwp; // phpcs:ignore
111 130 remove_action( 'admin_menu', array( $zohopwp, 'ccgclientportal_admin_menu' ) ); // phpcs:ignore
112 131 }
@@ -158,8 +177,16 @@
158 177
159 178 if ( Helper::is_gravity_perks_plugin_active() ) {
160 179 remove_action( 'admin_print_footer_scripts', array( 'GWPerks', 'welcome_pointer_script' ), 10 ); // phpcs:ignore
161 180 }
181 +
182 + $license_active = License::get_license_status();
183 + if ( false === $license_active ) {
184 + add_action( 'admin_notices', array( $this, 'lasso_lite_custom_dashboard_banner' ) );
185 + }
186 +
187 + add_action( 'wp_footer', array( $this, 'lasso_lite_event_tracking' ) );
188 + add_action( 'admin_footer', array( $this, 'open_links_in_new_tab' ) );
162 189 }
163 190
164 191
165 192 /**
@@ -199,13 +226,15 @@
199 226 wp_redirect( Page::get_page_url() ); // phpcs:ignore
200 227 exit;
201 228 }
202 229
203 - // ? Reset onboarding for testing
230 + // ? Reset onboarding for testing (one-shot: strip QA param so step persistence works on reload)
204 231 $reset_onboarding = Helper::GET()[ Enum::RESET_WELCOME_PAGE ] ?? '';
205 232 if ( $reset_onboarding ) {
206 - Helper::update_option( Enum::IS_VISITED_WELCOME_PAGE, 0 );
207 - update_option( Enum::LASSO_LITE_ACTIVE, 1 );
233 + Helper::reset_onboarding_for_testing();
234 +
235 + wp_safe_redirect( remove_query_arg( Enum::RESET_WELCOME_PAGE ) ); // phpcs:ignore WordPress.Security.SafeRedirect.wp_redirect_wp_redirect
236 + exit;
208 237 }
209 238
210 239 // ? Reset request review for testing
211 240 $reset_review = Helper::GET()[ Enum::RESET_REQUEST_REVIEW ] ?? '';
@@ -216,9 +245,9 @@
216 245 }
217 246
218 247 // ? The new Lasso Lite active should be redirect to welcome page
219 248 $onboarding_page = Helper::add_prefix_page( Enum::PAGE_ONBOARDING );
220 - $should_redirect_to_welcome_page = get_option( Enum::LASSO_LITE_ACTIVE ) && ! Helper::get_option( Enum::IS_VISITED_WELCOME_PAGE );
249 + $should_redirect_to_welcome_page = self::should_redirect_to_welcome_page();
221 250 if ( SIMPLE_URLS_SLUG === $post_type && $onboarding_page !== $get_page && $should_redirect_to_welcome_page ) {
222 251 wp_redirect( Page::get_page_url( $onboarding_page ) ); // phpcs:ignore
223 252 exit;
224 253 } elseif ( $onboarding_page === $get_page && ! $should_redirect_to_welcome_page ) {
@@ -315,14 +344,18 @@
315 344 Helper::enqueue_style( 'bootstrap-select-css', 'bootstrap-select.min.css' );
316 345 Helper::enqueue_style( 'simple-panigation-css', 'simplePagination.css' );
317 346 Helper::enqueue_style( 'select2-css', 'select2.min.css' );
318 347 Helper::enqueue_style( 'lasso-quill', 'quill.snow.css' );
319 - Helper::enqueue_style( 'lasso-live', 'lasso-live.css', array(), 'all', false );
348 + Helper::enqueue_style( 'lasso-lite', 'lasso-lite.css' );
320 349 Helper::enqueue_style( 'lasso-display-modal', 'lasso-display-modal.css' );
321 350 Helper::enqueue_style( 'lasso-dashboard', 'lasso-dashboard.css' );
322 351 Helper::enqueue_style( 'lasso-lite-custom', 'lite-custom.css' );
323 352 }
324 353
354 + if ( $setting->is_setting_amazon_page() ) {
355 + Helper::enqueue_style( 'settings-amazon-modal', 'settings-amazon-modal.css', array( SIMPLE_URLS_SLUG . '-lasso-lite-custom' ) );
356 + }
357 +
325 358 if ( $setting->is_setting_display_page() || $setting->is_setting_onboarding_page() ) {
326 359 Helper::enqueue_style( 'spectrum', 'spectrum.min.css' );
327 360 }
328 361
@@ -331,11 +364,17 @@
331 364 Helper::enqueue_style( 'bootstrap-grid-css', 'bootstrap-grid.min.css' );
332 365 Helper::enqueue_style( 'lasso-display-modal', 'lasso-display-modal.css' );
333 366 Helper::enqueue_style( 'simple-pagination', 'simplePagination.css' );
334 367 Helper::enqueue_style( 'lasso-quill', 'quill.snow.css' );
335 - Helper::enqueue_style( 'lasso-live', 'lasso-live.css', array(), 'all', false );
368 + Helper::enqueue_style( 'lasso-lite', 'lasso-lite.css' );
369 + Helper::enqueue_style( 'lasso-modal-css', 'lasso-modal.css' );
336 370 }
337 371
372 + global $pagenow; // phpcs:ignore
373 + if ( 'index.php' === $pagenow && $this->should_show_dashboard_promo_banner() ) {
374 + Helper::enqueue_style( 'lasso-lite-admin', 'lasso-lite-admin.css' );
375 + }
376 +
338 377 // @codingStandardsIgnoreEnd
339 378 }
340 379
341 380 /**
@@ -344,8 +383,9 @@
344 383 public function add_scripts() {
345 384 if ( ! Helper::is_lite_using_new_ui() ) {
346 385 return;
347 386 }
387 + global $pagenow; // phpcs:ignore
348 388
349 389 $get = Helper::GET(); // phpcs:ignore
350 390 $page = $get['page'] ?? false;
351 391 $setting = new Setting();
@@ -356,24 +396,48 @@
356 396 $data_passed_to_js = array(
357 397 'ajax_url' => admin_url( 'admin-ajax.php' ),
358 398 'site_url' => site_url(),
359 399 'plugin_url' => SIMPLE_URLS_URL,
400 + 'lasso_link' => Constant::LASSO_LINK,
401 + 'lasso_hub_url' => Constant::get_lasso_hub_url(),
402 + 'upgrade_url' => Constant::LASSO_UPGRADE_URL,
360 403 'rewrite_slug_default' => Enum::REWRITE_SLUG_DEFAULT,
361 404 'simple_urls_slug' => SIMPLE_URLS_SLUG,
362 405 'page_url_details' => Enum::PAGE_URL_DETAILS,
363 406 'setup_progress' => Helper::get_setup_progress_information(),
364 - 'optionsNonce' => wp_create_nonce( 'lasso_settings_save' ),
407 + 'optionsNonce' => wp_create_nonce( Constant::LASSO_LITE_NONCE . wp_salt() ),
365 408 'should_open_support_modal' => $support_enabled,
366 409 'amazon_tracking_id_regex' => Amazon_Api::TRACKING_ID_REGEX,
367 410 'is_onboard_page' => $setting->is_setting_onboarding_page(),
411 + 'onboarding_current_step' => $setting->is_setting_onboarding_page()
412 + ? Helper::get_onboarding_current_step( Helper::should_show_import_page() )
413 + : 'welcome',
368 414 'block_customize' => Constant::BLOCK_CUSTOMIZE,
415 + 'userId' => Helper::get_option( Constant::LASSO_ACCOUNT_USER_ID ),
369 416 );
417 + $data_passed_to_js['realtime'] = Realtime_Click::get_js_config();
370 418
419 + if ( $setting->is_setting_amazon_page() ) {
420 + // Amazon settings only: edit.php?post_type=surl&page=surl-settings-amazon
421 + $data_passed_to_js['lite_account_existing_always_post'] = true;
422 + $data_passed_to_js['lite_amazon_settings_post_signup_verify_creators'] = true;
423 + }
424 +
371 425 if ( SIMPLE_URLS_SLUG === $post_type ) {
372 426 wp_dequeue_script( 'up_admin_script' ); // ? fix js conflict with plugin: Download plugin
373 427 }
374 428
375 429 // @codingStandardsIgnoreStart
430 + if ( 'index.php' === $pagenow && $this->should_show_dashboard_promo_banner() ) {
431 + $data_passed_to_js = array(
432 + 'ajax_url' => admin_url( 'admin-ajax.php' ),
433 + 'optionsNonce' => wp_create_nonce( Constant::LASSO_LITE_NONCE . wp_salt() ),
434 + );
435 + wp_enqueue_script( 'jquery' );
436 + wp_localize_script( 'jquery', 'lassoLiteOptionsData', $data_passed_to_js );
437 + Helper::enqueue_script( 'lasso-lite-admin-js', 'lasso-lite-admin.js', array( 'jquery' ), false );
438 + }
439 +
376 440 if ( $setting->is_wordpress_post() || $setting->is_surls_page() || $setting->is_custom_post() ) {
377 441 wp_enqueue_script( 'jquery-migrate' ); // ? fix jQuery(...).live is not a function
378 442 wp_enqueue_script( 'jquery' );
379 443 wp_enqueue_script( 'jquery-effects-core' );
@@ -387,8 +451,14 @@
387 451 Helper::enqueue_script( 'lasso-icons-brands', 'brands.min.js', array( 'jquery' ) );
388 452 Helper::enqueue_script( 'circle-progress', 'circle-progress.min.js', array( 'jquery' ) );
389 453
390 454 Helper::enqueue_script( 'lasso-quill', 'quill.min.js' );
455 + Helper::enqueue_script( 'lasso-modal-js', 'lasso-modal.js' );
456 +
457 + if ( ! Helper::is_classic_editor() && ( $setting->is_wordpress_post() || $setting->is_custom_post() ) ) {
458 + Helper::enqueue_script( 'lasso-lite-display-modal', 'lasso-lite-display-modal.js' );
459 + }
460 +
391 461 wp_enqueue_media();
392 462 Helper::enqueue_script( 'moment-js', 'moment.min.js', array( 'jquery' ) );
393 463 Helper::enqueue_script( 'select2-js', 'select2.full.min.js', array( 'jquery' ) );
394 464 Helper::enqueue_script( SIMPLE_URLS_SLUG . '-jq-auto-complete-js', 'jquery-autocomplete.js' );
@@ -402,8 +472,12 @@
402 472 wp_localize_script( 'jquery', 'lassoLiteOptionsData', $data_passed_to_js );
403 473 Helper::enqueue_script( 'lasso-helper', 'lasso-helper.js', array( 'jquery' ) );
404 474 Helper::enqueue_script( 'url-add', 'url-add.js', array( 'jquery' ) );
405 475 Helper::enqueue_script( 'support', 'support.js', array( 'jquery' ) );
476 +
477 + if ( ! $setting->is_setting_onboarding_page() && ! $setting->is_setting_amazon_page() ) {
478 + Helper::enqueue_script( 'lasso-signup', 'lasso-signup.js', array( 'jquery' ) );
479 + }
406 480
407 481 if ( SIMPLE_URLS_SLUG . '-' . Enum::PAGE_URL_DETAILS === $page ) {
408 482 Helper::enqueue_script( 'url-details', 'url-details.js', array( 'jquery' ) );
409 483 }
@@ -412,14 +486,25 @@
412 486 if ( $setting->is_dashboard_page() ) {
413 487 Helper::enqueue_script( 'dashboard', 'dashboard.js', array( 'jquery' ) );
414 488 }
415 489
490 + if ( $setting->is_opportunities_page() ) {
491 + Helper::enqueue_script( 'opportunities', 'opportunities.js', array( 'jquery' ) );
492 + }
493 +
494 + if ( $setting->is_tables_page() ) {
495 + Helper::enqueue_script( 'tables', 'tables.js', array( 'jquery' ) );
496 + }
497 +
416 498 if ( $setting->is_setting_display_page() || $setting->is_setting_onboarding_page() ) {
417 499 Helper::enqueue_script( 'spectrum-js', 'spectrum.min.js', array( 'jquery' ) );
418 500 Helper::enqueue_script( 'settings-display-js', 'settings-display.js', array( 'jquery' ) );
419 501 }
420 502
421 - if ( $setting->is_setting_amazon_page() || $setting->is_setting_onboarding_page() ) {
503 + if ( $setting->is_setting_amazon_page() ) {
504 + Helper::enqueue_script( 'lasso-signup', 'lasso-signup.js', array( 'jquery' ) );
505 + Helper::enqueue_script( 'settings-amazon', 'settings-amazon.js', array( 'jquery', SIMPLE_URLS_SLUG . '-lasso-signup' ) );
506 + } elseif ( $setting->is_setting_onboarding_page() ) {
422 507 Helper::enqueue_script( 'settings-amazon', 'settings-amazon.js', array( 'jquery' ) );
423 508 }
424 509
425 510 if ( $setting->is_import_page() || $setting->is_setting_onboarding_page() ) {
@@ -429,8 +514,9 @@
429 514 if ( $setting->is_setting_onboarding_page() ) {
430 515 Helper::enqueue_script( 'onboarding-js', 'onboarding.js', array( 'jquery' ) );
431 516 Helper::enqueue_script( 'settings-js', 'settings.js', array( 'jquery' ) );
432 517 Helper::enqueue_script( 'settings-display-js', 'settings-display.js', array( 'jquery' ) );
518 + Helper::enqueue_script( 'lasso-signup', 'lasso-signup.js', array( 'jquery' ) );
433 519 }
434 520
435 521 if ( $setting->is_setting_general_page() ) {
436 522 Helper::enqueue_script( 'settings-general', 'settings-general.js', array( 'jquery' ) );
@@ -435,8 +521,12 @@
435 521 if ( $setting->is_setting_general_page() ) {
436 522 Helper::enqueue_script( 'settings-general', 'settings-general.js', array( 'jquery' ) );
437 523 }
438 524
525 + if ( $setting->is_setting_page() ) {
526 + Helper::enqueue_script( 'settings-unsaved-guard', 'settings-unsaved-guard.js', array( 'jquery', SIMPLE_URLS_SLUG . '-lasso-helper' ) );
527 + }
528 +
439 529 if ( $setting->is_group_detail_page() || $setting->is_group_page() ) {
440 530 Helper::enqueue_script( 'groups', 'groups.js', array( 'jquery' ) );
441 531 }
442 532
@@ -446,9 +536,9 @@
446 536 /**
447 537 * DISPLAYS CSS FOR FRONTEND OF SITE
448 538 */
449 539 public function add_scripts_frontend() {
450 - Helper::enqueue_style( 'lasso-live', 'lasso-live.css', array(), 'all', false );
540 + Helper::enqueue_style( 'lasso-lite', 'lasso-lite.css' );
451 541 }
452 542
453 543 /**
454 544 * DISPLAYS CUSTOM CSS FOR FRONTEND OF SITE
@@ -457,23 +547,10 @@
457 547 if ( ! Helper::is_lite_using_new_ui() ) {
458 548 return;
459 549 }
460 550
461 - $settings = Setting::get_settings();
462 -
463 551 // @codingStandardsIgnoreStart
464 - echo '<style type="text/css">
465 - :root{
466 - --lasso-main: ' . $settings['display_color_main'] . ' !important;
467 - --lasso-title: ' . $settings['display_color_title'] . ' !important;
468 - --lasso-button: ' . $settings['display_color_button'] . ' !important;
469 - --lasso-secondary-button: ' . $settings['display_color_secondary_button'] . ' !important;
470 - --lasso-button-text: ' . $settings['display_color_button_text'] . ' !important;
471 - --lasso-background: ' . $settings['display_color_background'] . ' !important;
472 - --lasso-pros: ' . $settings['display_color_pros'] . ' !important;
473 - --lasso-cons: ' . $settings['display_color_cons'] . ' !important;
474 - }
475 - </style>';
552 + echo '<style type="text/css">' . Helper::get_lasso_display_css_variables( true ) . '</style>';
476 553
477 554 // fix fontawesome js render svg (from other plugins) instead of using css
478 555 echo '
479 556 <script type="text/javascript">
@@ -533,8 +610,20 @@
533 610 'manage_options',
534 611 Constant::LASSO_SUPPORT_URL,
535 612 );
536 613
614 + $new_submenu[93] = array(
615 + 'Analytics',
616 + 'manage_options',
617 + Constant::LASSO_ANALYTICS_URL,
618 + );
619 +
620 + $new_submenu[95] = array(
621 + 'Marketplace',
622 + 'manage_options',
623 + Constant::LASSO_AFFILIATE_PLUS_URL,
624 + );
625 +
537 626 $new_submenu[100] = array(
538 627 '<b class="green">Upgrade to Pro</b>',
539 628 'manage_options',
540 629 Constant::LASSO_UPGRADE_URL,
@@ -546,13 +635,41 @@
546 635 $submenu[ $menu_key ] = $new_submenu;
547 636 }
548 637
549 638 /**
639 + * Lasso display styles + color variables inside the block editor iframe (WP 7+).
640 + *
641 + * admin_enqueue_scripts only loads into the parent editor chrome; shortcode HTML
642 + * preview renders in the editor canvas iframe and needs enqueue_block_assets.
643 + *
644 + * @codeCoverageIgnore Coverage ignore.
645 + */
646 + public function lasso_block_editor_css_variables() {
647 + if ( ! is_admin() || Helper::is_lasso_pro_installed() || ! Helper::is_lite_using_new_ui() ) {
648 + return;
649 + }
650 +
651 + $setting = new Setting();
652 + if ( ! $setting->is_wordpress_post() && ! $setting->is_custom_post() ) {
653 + return;
654 + }
655 +
656 + Helper::enqueue_style( 'bootstrap-grid-css', 'bootstrap-grid.min.css' );
657 + Helper::enqueue_style( 'lasso-lite', 'lasso-lite.css' );
658 + wp_add_inline_style( SIMPLE_URLS_SLUG . '-lasso-lite', Helper::get_lasso_display_css_variables( true ) );
659 + }
660 +
661 + /**
550 662 * Load lasso js file in Gutenberg editor
551 663 */
552 664 public function lasso_lite_gutenberg_block() {
553 665 if ( ! Helper::is_lasso_pro_installed() ) {
554 - Helper::enqueue_script( 'lasso-lite-gutenberg-block', 'lasso-lite-gutenberg-block.js', array( 'wp-blocks', 'wp-editor' ), true );
666 + Helper::enqueue_script(
667 + 'lasso-lite-gutenberg-block',
668 + 'lasso-lite-gutenberg-block.js',
669 + array( 'wp-blocks', 'wp-block-editor', 'wp-element', 'wp-components', 'wp-compose' ),
670 + true
671 + );
555 672 Helper::enqueue_script( 'display-add', 'display-add.js', array( 'jquery' ) );
556 673 Helper::enqueue_script( 'url-add', 'url-add.js', array( 'jquery' ) );
557 674 }
558 675 }
@@ -564,10 +681,10 @@
564 681 */
565 682 public function lasso_add_tinymce_plugin( $plugin_array ) {
566 683 if ( ! Helper::is_lasso_pro_plugin_active() ) {
567 684 $lasso_setting = new Setting();
568 - if ( Helper::is_classic_editor_plugin_active() && ( $lasso_setting->is_wordpress_post() || $lasso_setting->is_custom_post() ) ) {
569 - $plugin_array['lasso_lite_tc_button'] = SIMPLE_URLS_URL . '/admin/assets/js/lasso-lite-display-modal.js?v=' . strval( @filemtime( SIMPLE_URLS_DIR . '/admin/assets/js/lasso-display-modal.js' ) ); // phpcs:ignore
685 + if ( Helper::is_classic_editor() && ( $lasso_setting->is_wordpress_post() || $lasso_setting->is_custom_post() ) ) {
686 + $plugin_array['lasso_lite_tc_button'] = SIMPLE_URLS_URL . '/admin/assets/js/lasso-lite-display-modal.js?v=' . strval( @filemtime( SIMPLE_URLS_DIR . '/admin/assets/js/lasso-lite-display-modal.js' ) ); // phpcs:ignore
570 687 Helper::enqueue_script( 'display-add', 'display-add.js', array( 'jquery' ) );
571 688 Helper::enqueue_script( 'url-add', 'url-add.js', array( 'jquery' ) );
572 689 }
573 690 }
@@ -599,9 +716,9 @@
599 716 if ( $lasso_setting->is_wordpress_post() || $lasso_setting->is_custom_post() ) {
600 717 $current_screen = get_current_screen();
601 718 // ? Check to make sure render html only block editor Gutenberg
602 719 if ( ( method_exists( $current_screen, 'is_block_editor' ) && $current_screen->is_block_editor() )
603 - || ( function_exists( 'is_gutenberg_page' ) ) && is_gutenberg_page()
720 + || ( function_exists( 'is_gutenberg_page' ) && is_gutenberg_page() )
604 721 ) {
605 722 echo Helper::get_display_modal_html(); // phpcs:ignore
606 723 }
607 724 }
@@ -826,6 +943,609 @@
826 943 );
827 944 }
828 945
829 946 return $text;
947 + }
948 +
949 + /**
950 + * Open Affiliate+ in new tab
951 + */
952 + public function open_links_in_new_tab() {
953 + ?>
954 + <script type="text/javascript">
955 + jQuery(document).ready(function($) {
956 + $('a[href="https://app.getlasso.co/plus/"]').attr('target', '_blank');
957 + });
958 + </script>
959 + <?php
960 + }
961 +
962 + /**
963 + * Whether Lite onboarding should redirect admin users to the welcome flow.
964 + *
965 + * @return bool
966 + */
967 + public static function should_redirect_to_welcome_page() {
968 + return (bool) get_option( Enum::LASSO_LITE_ACTIVE ) && ! Helper::get_option( Enum::IS_VISITED_WELCOME_PAGE );
969 + }
970 +
971 + /**
972 + * Whether the affiliate promo dashboard banner should render.
973 + *
974 + * @return bool
975 + */
976 + private function should_show_dashboard_promo_banner() {
977 + global $pagenow;
978 +
979 + if ( 'index.php' !== $pagenow || ! Helper::is_lite_using_new_ui() ) {
980 + return false;
981 + }
982 +
983 + $license_active = License::get_license_status();
984 + $is_connected_aff = intval( Helper::get_option( Constant::LASSO_OPTION_IS_CONNECTED_AFFILIATE, '0' ) );
985 +
986 + return ! $license_active
987 + && 0 === $is_connected_aff
988 + && ! intval( Helper::get_option( Constant::LASSO_OPTION_DISMISS_PROMOTIONS, 0 ) );
989 + }
990 +
991 + /**
992 + * Show Performance promotion
993 + *
994 + * @return void
995 + */
996 + public function lasso_lite_custom_dashboard_banner() {
997 + if ( ! $this->should_show_dashboard_promo_banner() ) {
998 + echo ''; // phpcs:ignore
999 + return;
1000 + }
1001 +
1002 + $setting_data = Setting::get_settings();
1003 + $support_enabled = $setting_data[ Enum::SUPPORT_ENABLED ] ?? false;
1004 + if ( ! $support_enabled ) {
1005 + $template_path = '/admin/views/notifications/affiliate-promotions-no-intercom.php';
1006 + } else {
1007 + $template_path = '/admin/views/notifications/affiliate-promotions-intercom.php';
1008 + }
1009 +
1010 + $html = Helper::include_with_variables(
1011 + SIMPLE_URLS_DIR . $template_path,
1012 + array(
1013 + 'dismiss' => 0,
1014 + 'option_name' => Constant::LASSO_OPTION_DISMISS_PROMOTIONS,
1015 + )
1016 + );
1017 +
1018 + echo $html; // phpcs:ignore
1019 + }
1020 +
1021 + /**
1022 + * Print JS script for Lasso event tracking.
1023 + */
1024 + public function lasso_lite_event_tracking() {
1025 + if ( is_admin() || strpos( Helper::get_server_param( 'REQUEST_URI' ), 'wp-admin' )
1026 + || strpos( Helper::get_server_param( 'REQUEST_URI' ), 'elementor-preview' )
1027 + || Helper::is_lasso_pro_installed()
1028 + ) {
1029 + return;
1030 + }
1031 +
1032 + $process_lasso_event_tracking = apply_filters( 'lasso_lite_event_tracking', true );
1033 +
1034 + if ( ! $process_lasso_event_tracking ) {
1035 + return;
1036 + }
1037 +
1038 + $lasso_options = Setting::get_settings();
1039 + $is_ip_anonymization = false;
1040 + $lsid = Helper::build_lsid();
1041 + $realtime_ingest = null;
1042 + if ( Realtime_Click::is_ingest_enabled() ) {
1043 + $ingest_secret = Realtime_Click::get_ingest_secret();
1044 + $channel_id = Realtime_Click::get_channel_id();
1045 + if ( is_string( $ingest_secret ) && '' !== $ingest_secret && is_string( $channel_id ) && '' !== $channel_id ) {
1046 + $beacon = Realtime_Click::get_beacon_credentials( $channel_id, $ingest_secret );
1047 + $realtime_ingest = array(
1048 + 'ajaxUrl' => admin_url( 'admin-ajax.php' ),
1049 + 'action' => 'lasso_lite_realtime_ingest',
1050 + 'channelId' => $channel_id,
1051 + 'beaconToken' => $beacon['token'],
1052 + 'beaconBucket' => $beacon['bucket'],
1053 + );
1054 + }
1055 + }
1056 +
1057 + $current_date = gmdate( 'Ymd' );
1058 + $js_version = LASSO_LITE_VERSION . '.' . $current_date;
1059 +
1060 + // Prefer clean path when permalinks are enabled; fall back to query when using Plain
1061 + $snippet_query = Helper::get_snippet_query();
1062 + $performance_url_hash = add_query_arg(
1063 + array(
1064 + $snippet_query => '1',
1065 + 'ver' => $js_version,
1066 + ),
1067 + home_url( '/' )
1068 + );
1069 +
1070 + $default_js_domain = 'https://js.codedrink.com';
1071 +
1072 + $dynamic_js_domain = Helper::get_option( 'js_domain', $default_js_domain );
1073 + $full_dynamic_js_domain = Helper::get_option( 'full_js_domain', "$dynamic_js_domain/snippet.min.js" );
1074 +
1075 + $dynamic_performance_url_external = $full_dynamic_js_domain . '?ver=' . $js_version; // load external js
1076 +
1077 + // @codeCoverageIgnoreStart
1078 + if ( $lasso_options['performance_event_tracking'] ) :
1079 + ?>
1080 +
1081 + <script type="text/javascript">
1082 + (function () {
1083 + // Prevent double-insert
1084 + if (window.LS_AFF_IS_LOADED || window.__LS_SEQ_LOADER__) {
1085 + return;
1086 + }
1087 + window.__LS_SEQ_LOADER__ = true;
1088 + var lsSources = [
1089 + <?php echo wp_json_encode( $dynamic_performance_url_external ); ?>,
1090 + <?php echo wp_json_encode( $performance_url_hash ); ?>
1091 + ];
1092 +
1093 + var lsScriptLoadTimeoutMs = 2500;
1094 + var lsIndex = 0, lsTimeoutMs = lsScriptLoadTimeoutMs;
1095 +
1096 + function lsLoadNext() {
1097 + if (window.LS_AFF_IS_LOADED || lsIndex >= lsSources.length) {
1098 + return;
1099 + }
1100 +
1101 + var lsUrl = lsSources[lsIndex++];
1102 + var lsScript = document.createElement('script');
1103 + lsScript.src = lsUrl;
1104 + lsScript.onerror = function () {
1105 + try { lsScript.remove(); } catch (_) {}
1106 + if (!window.LS_AFF_IS_LOADED) lsLoadNext();
1107 + };
1108 + var lsTimer = setTimeout(function () {
1109 + if (!window.LS_AFF_IS_LOADED) {
1110 + try { lsScript.remove(); } catch (_) {}
1111 + lsLoadNext();
1112 + }
1113 + }, lsTimeoutMs);
1114 + lsScript.onload = (function (orig) {
1115 + return function () {
1116 + clearTimeout(lsTimer);
1117 + if (orig) orig();
1118 + };
1119 + })(lsScript.onload);
1120 + (document.head || document.documentElement).appendChild(lsScript);
1121 + }
1122 +
1123 + lsLoadNext();
1124 + })();
1125 + </script>
1126 + <script type="text/javascript">
1127 + (function(){
1128 + <?php if ( null !== $realtime_ingest ) : ?>
1129 + window.LASSO_LITE_REALTIME_INGEST = <?php echo wp_json_encode( $realtime_ingest ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>;
1130 + <?php endif; ?>
1131 + var lsInitialized = false;
1132 + function lsDoInit(detail){
1133 + if (lsInitialized) return;
1134 + lsInitialized = true;
1135 + try {
1136 + (detail && detail.init ? detail : (window.LSAFFEvents || {})).init({
1137 + 'lsid': '<?php echo $lsid; // phpcs:ignore ?>',
1138 + 'pid': '<?php echo get_the_ID(); // phpcs:ignore ?>',
1139 + 'ipa': '<?php echo $is_ip_anonymization; // phpcs:ignore ?>',
1140 + 'performance': '1',
1141 + 'matching': '<?php echo $lasso_options['auto_upgrade_eligible_links'] ? 1 : 0; ?>',
1142 + });
1143 + } catch (err) {
1144 + }
1145 + }
1146 +
1147 + var lsPollCount = 0;
1148 + var lsMaxPollAttempts = 50;
1149 + var lsPollTimer = null;
1150 + function lsStartPolling() {
1151 + if (lsPollTimer) return;
1152 + lsPollTimer = setInterval(function(){
1153 + if (lsInitialized) { clearInterval(lsPollTimer); return; }
1154 + if (window.LSAFFEvents && typeof window.LSAFFEvents.init === 'function') {
1155 + lsDoInit(window.LSAFFEvents);
1156 + clearInterval(lsPollTimer);
1157 + return;
1158 + }
1159 + lsPollCount++;
1160 + if (lsPollCount > lsMaxPollAttempts) { // ~5s at 100ms
1161 + clearInterval(lsPollTimer);
1162 + }
1163 + }, 100);
1164 + }
1165 +
1166 + if (window.LSAFFEvents && typeof window.LSAFFEvents.init === 'function') {
1167 + lsDoInit(window.LSAFFEvents);
1168 + } else {
1169 + document.addEventListener('LSAFFEventLoaded', function(e){
1170 + lsDoInit(e.detail);
1171 + }, { once: true });
1172 + lsStartPolling();
1173 + }
1174 + })();
1175 + </script>
1176 + <?php
1177 + endif;
1178 + // @codeCoverageIgnoreEnd
1179 + }
1180 +
1181 + /**
1182 + * Elementor Init Hook
1183 + *
1184 + * @codeCoverageIgnore Coverage ignore.
1185 + */
1186 + public function elementor_init() {
1187 + // ? This runs on elementor/init only — Pro owns Elementor when affiliate-plugin is active.
1188 + if ( Helper::is_lasso_pro_installed() ) {
1189 + return;
1190 + }
1191 +
1192 + // ? Do not gate on is_plugin_active( 'elementor/elementor.php' ): custom paths / load order can false-negative while Elementor is clearly bootstrapped (this hook).
1193 + if ( class_exists( 'Elementor\Widget_Base' ) && class_exists( 'Elementor\Controls_Manager' ) ) {
1194 + add_action( 'elementor/widgets/register', array( $this, 'register_widget_lasso_shortcode' ) );
1195 + add_action( 'elementor/editor/before_enqueue_styles', array( $this, 'elementor_editor_styles' ) );
1196 + add_action( 'elementor/editor/before_enqueue_scripts', array( $this, 'elementor_editor_scripts' ) );
1197 + }
1198 +
1199 + // ? Move the scan post into the "elementor/document/after_save" action
1200 + add_action( 'elementor/document/after_save', array( $this, 'after_elementor_document_save' ), 10, 1 );
1201 + }
1202 +
1203 + /**
1204 + * Register lasso widget
1205 + *
1206 + * @param object $widgets_manager Widget manager.
1207 + *
1208 + * @codeCoverageIgnore Coverage ignore.
1209 + */
1210 + public function register_widget_lasso_shortcode( $widgets_manager ) {
1211 + require_once SIMPLE_URLS_PLUGIN_PATH . '/libs/elementor/widgets/lasso-shortcode.php';
1212 + $widgets_manager->register( new \Widget_Lasso_Shortcode() );
1213 + }
1214 +
1215 + /**
1216 + * Elementor load css
1217 + *
1218 + * @codeCoverageIgnore Coverage ignore.
1219 + */
1220 + public function elementor_editor_styles() {
1221 + wp_enqueue_style( 'wp-pointer' );
1222 + Helper::enqueue_style( 'lasso-elementor', 'lasso-elementor.css' );
1223 + }
1224 +
1225 + /**
1226 + * Elementor editor scripts (parity with Pro wp-pointer).
1227 + *
1228 + * @codeCoverageIgnore Coverage ignore.
1229 + */
1230 + public function elementor_editor_scripts() {
1231 + wp_enqueue_script( 'wp-pointer' );
1232 + if ( ! Helper::is_lite_using_new_ui() ) {
1233 + return;
1234 + }
1235 + wp_enqueue_script( 'jquery' );
1236 + Helper::enqueue_script( 'lasso-modal-js', 'lasso-modal.js', array( 'jquery' ), true );
1237 + Helper::enqueue_script( 'lasso-elementor', 'lasso-elementor.js', array( 'jquery', SIMPLE_URLS_SLUG . '-lasso-modal-js' ), true );
1238 + Helper::enqueue_script( 'lasso-lite-display-modal', 'lasso-lite-display-modal.js', array( 'jquery', SIMPLE_URLS_SLUG . '-lasso-elementor' ), true );
1239 + }
1240 +
1241 + /**
1242 + * Move the scan post into the "elementor/document/after_save" action
1243 + *
1244 + * @param object $document Elementor document.
1245 + *
1246 + * @codeCoverageIgnore Coverage ignore.
1247 + */
1248 + public function after_elementor_document_save( $document ) {
1249 + $post = $document->get_post();
1250 + }
1251 +
1252 + /**
1253 + * Exclude Lasso performance JS from WP Rocket cache
1254 + *
1255 + * @param array $excluded_js Excluded JS.
1256 + * @return array
1257 + */
1258 + public function exclude_lasso_performance_js_from_rocket_cache( $excluded_js ) {
1259 + $excluded_js[] = 'lasso-performance.min.js';
1260 + return $excluded_js;
1261 + }
1262 +
1263 + /**
1264 + * Check is Elementor editor page
1265 + *
1266 + * @return bool
1267 + */
1268 + public static function is_editor() {
1269 + $http_referer = Helper::get_server_param( 'HTTP_REFERER' );
1270 + $query_str = wp_parse_url( $http_referer, PHP_URL_QUERY );
1271 + parse_str( $query_str, $query_params );
1272 +
1273 + return isset( $query_params['action'] ) && 'elementor' === $query_params['action'];
1274 + }
1275 +
1276 + /**
1277 + * Register rewrite rule for /js/connect-snippet.min.js
1278 + */
1279 + public static function lasso_register_connect_snippet_rewrite() {
1280 + $snippet_query = Helper::get_snippet_query();
1281 + add_rewrite_rule( '^js/snippet\.min\.js$', 'index.php?' . $snippet_query . '=1', 'top' );
1282 +
1283 + $beacon_path = ltrim( LASSO_BEACON_VANITY_PATH, '/' );
1284 + $beacon_rule = '^' . preg_quote( $beacon_path, '/' ) . '$';
1285 + add_rewrite_rule( $beacon_rule, 'index.php?' . LASSO_BEACON_QUERY . '=1', 'top' );
1286 + }
1287 +
1288 + /**
1289 + * Flush rewrites after plugin upgrades via WP upgrader
1290 + *
1291 + * @param object $upgrader Upgrader instance.
1292 + * @param array $options Upgrader options.
1293 + * @return void
1294 + */
1295 + public function lasso_connect_snippet_flush_on_upgrade( $upgrader, $options ) {
1296 + if ( empty( $options['type'] ) || 'plugin' !== $options['type'] ) {
1297 + return;
1298 + }
1299 +
1300 + // ? Supported actions: update (bulk/single) and install (upload .zip)
1301 + $action = isset( $options['action'] ) ? $options['action'] : '';
1302 + if ( ! in_array( $action, array( 'update', 'install' ), true ) ) {
1303 + return;
1304 + }
1305 +
1306 + $targets = array();
1307 + if ( ! empty( $options['plugins'] ) && is_array( $options['plugins'] ) ) {
1308 + $targets = $options['plugins'];
1309 + } elseif ( ! empty( $options['plugin'] ) && is_string( $options['plugin'] ) ) {
1310 + $targets = array( $options['plugin'] );
1311 + }
1312 +
1313 + // ? Fallback detection using Plugin_Upgrader->new_plugin_data when targets are missing
1314 + if ( empty( $targets ) && is_object( $upgrader ) && $upgrader instanceof \Plugin_Upgrader ) {
1315 + $plugin_data = isset( $upgrader->new_plugin_data ) ? $upgrader->new_plugin_data : array();
1316 + $plugin_name = is_array( $plugin_data ) && isset( $plugin_data['Name'] ) ? $plugin_data['Name'] : '';
1317 + if ( 'Lasso Lite' === $plugin_name ) {
1318 + $this->lasso_register_connect_snippet_rewrite();
1319 + flush_rewrite_rules();
1320 + return;
1321 + }
1322 + }
1323 +
1324 + if ( empty( $targets ) ) {
1325 + return;
1326 + }
1327 +
1328 + $plugin_file = plugin_basename( SIMPLE_URLS_PLUGIN_PATH . '/plugin.php' );
1329 + if ( in_array( $plugin_file, $targets, true ) ) {
1330 + $this->lasso_register_connect_snippet_rewrite();
1331 + flush_rewrite_rules();
1332 + }
1333 + }
1334 +
1335 + /**
1336 + * One-time rewrite flush after upgrade so /js/e is persisted (upgrader runs old code).
1337 + *
1338 + * @return void
1339 + */
1340 + public function maybe_flush_vanity_rewrites_on_upgrade() {
1341 + if ( '1' !== (string) Helper::get_option( 'pending_vanity_rewrite_flush', '0' ) ) {
1342 + return;
1343 + }
1344 +
1345 + self::lasso_register_connect_snippet_rewrite();
1346 + flush_rewrite_rules();
1347 + Helper::update_option( 'pending_vanity_rewrite_flush', '0' );
1348 + }
1349 +
1350 + /**
1351 + * Allow lasso_connect_snippet as query var
1352 + *
1353 + * @param array $vars Query vars.
1354 + * @return array
1355 + */
1356 + public function lasso_connect_snippet_query_var( $vars ) {
1357 + $snippet_query = Helper::get_snippet_query();
1358 + $vars[] = $snippet_query;
1359 + $vars[] = LASSO_BEACON_QUERY;
1360 + return $vars;
1361 + }
1362 +
1363 + /**
1364 + * Serve vanity JS: /js/connect-snippet.min.js
1365 + *
1366 + * Outputs the connect-snippet.min.js from plugin assets with proper caching headers.
1367 + */
1368 + public function serve_connect_snippet() {
1369 + $snippet_query = Helper::get_snippet_query();
1370 + // Allow serving by pretty path even if rewrite rules aren't flushed yet
1371 + $req_uri = Helper::get_server_param( 'REQUEST_URI' );
1372 + $req_path = is_string( $req_uri ) ? wp_parse_url( $req_uri, PHP_URL_PATH ) : '';
1373 + $is_snippet_path = is_string( $req_path ) && rtrim( $req_path, '/' ) === LASSO_SNIPPET_VANITY_PATH_LITE;
1374 + if ( intval( get_query_var( $snippet_query ) ) !== 1 && ! $is_snippet_path ) {
1375 + return;
1376 + }
1377 +
1378 + $file_path = LASSO_CONNECT_SNIPPET_FILE_LITE;
1379 + if ( ! file_exists( $file_path ) ) {
1380 + status_header( 404 );
1381 + exit;
1382 + }
1383 +
1384 + // Headers
1385 + header( 'Content-Type: application/javascript; charset=UTF-8' );
1386 + header( 'X-Content-Type-Options: nosniff' );
1387 +
1388 + // Cache headers with support for 304
1389 + $last_modified = gmdate( 'D, d M Y H:i:s', filemtime( $file_path ) ) . ' GMT';
1390 + $etag = 'W/"' . md5( $last_modified . filesize( $file_path ) ) . '"';
1391 +
1392 + header( 'Last-Modified: ' . $last_modified );
1393 + header( 'ETag: ' . $etag );
1394 +
1395 + // Cache: If version query is present, cache for 1 day; else short TTL
1396 + $ver = isset( $_GET['ver'] ) ? sanitize_text_field( wp_unslash( $_GET['ver'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
1397 + if ( ! empty( $ver ) ) {
1398 + header( 'Cache-Control: public, max-age=86400' );
1399 + } else {
1400 + header( 'Cache-Control: public, max-age=300' );
1401 + }
1402 +
1403 + // Handle conditional requests
1404 + $if_none_match = isset( $_SERVER['HTTP_IF_NONE_MATCH'] ) ? sanitize_text_field( trim( wp_unslash( $_SERVER['HTTP_IF_NONE_MATCH'] ) ) ) : '';
1405 + $if_modified_since = isset( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ) ? sanitize_text_field( trim( wp_unslash( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ) ) ) : '';
1406 +
1407 + if ( $if_none_match === $etag || $if_modified_since === $last_modified ) {
1408 + status_header( 304 );
1409 + exit;
1410 + }
1411 +
1412 + ob_start();
1413 + $read_result = @readfile( $file_path );
1414 + if ( false === $read_result ) {
1415 + if ( ob_get_length() ) {
1416 + ob_end_clean();
1417 + }
1418 + status_header( 500 );
1419 + exit;
1420 + }
1421 + ob_end_flush();
1422 + exit;
1423 + }
1424 +
1425 + /**
1426 + * Resolve a beacon proxy request when path or query var matches.
1427 + *
1428 + * @param string|null $raw_body Optional body override for tests; null reads php://input.
1429 + * @return array{status:int,body:string}|null Null when not a beacon request.
1430 + */
1431 + public function resolve_beacon_proxy_request( $raw_body = null ) {
1432 + $req_uri = Helper::get_server_param( 'REQUEST_URI' );
1433 + $req_path = is_string( $req_uri ) ? wp_parse_url( $req_uri, PHP_URL_PATH ) : '';
1434 + $is_path = is_string( $req_path ) && rtrim( $req_path, '/' ) === LASSO_BEACON_VANITY_PATH;
1435 + $is_query = 1 === intval( get_query_var( LASSO_BEACON_QUERY ) );
1436 + if ( ! $is_path && ! $is_query ) {
1437 + return null;
1438 + }
1439 +
1440 + $method = Helper::get_server_param( 'REQUEST_METHOD' );
1441 + if ( null === $raw_body ) {
1442 + $raw_body = Beacon_Proxy::read_bounded_body();
1443 + }
1444 +
1445 + return $this->handle_beacon_proxy( $method ? $method : 'GET', $raw_body );
1446 + }
1447 +
1448 + /**
1449 + * Send beacon proxy HTTP response (no exit).
1450 + *
1451 + * @param array{status:int,body:string} $result Response from handle_beacon_proxy.
1452 + * @return void
1453 + */
1454 + public function emit_beacon_proxy_response( $result ) {
1455 + status_header( intval( $result['status'] ) );
1456 + header( 'Content-Type: text/plain; charset=UTF-8' );
1457 + header( 'Cache-Control: no-store' );
1458 + if ( '' !== $result['body'] ) {
1459 + echo $result['body']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1460 + }
1461 + }
1462 +
1463 + /**
1464 + * First-party POST /js/e → codedrink.com/js/e (EasyPrivacy).
1465 + */
1466 + public function serve_beacon_proxy() {
1467 + $result = $this->resolve_beacon_proxy_request();
1468 + if ( null === $result ) {
1469 + return;
1470 + }
1471 +
1472 + $this->emit_beacon_proxy_response( $result );
1473 + exit;
1474 + }
1475 +
1476 + /**
1477 + * Plan and forward a beacon request (testable core of serve_beacon_proxy).
1478 + *
1479 + * @param string $method HTTP method.
1480 + * @param string $raw_body Raw request body.
1481 + * @return array{status:int,body:string}
1482 + */
1483 + public function handle_beacon_proxy( $method, $raw_body ) {
1484 + $plan = Beacon_Proxy::plan( $method, is_string( $raw_body ) ? $raw_body : '' );
1485 +
1486 + if ( empty( $plan['ok'] ) ) {
1487 + return array(
1488 + 'status' => intval( $plan['status'] ),
1489 + 'body' => '',
1490 + );
1491 + }
1492 +
1493 + $response = wp_remote_post(
1494 + $plan['upstream'],
1495 + array(
1496 + 'timeout' => 3,
1497 + 'sslverify' => true,
1498 + 'headers' => array(
1499 + 'Content-Type' => 'text/plain; charset=utf-8',
1500 + ),
1501 + 'body' => $plan['body'],
1502 + )
1503 + );
1504 +
1505 + if ( is_wp_error( $response ) ) {
1506 + return array(
1507 + 'status' => 200,
1508 + 'body' => '',
1509 + );
1510 + }
1511 +
1512 + $status = intval( wp_remote_retrieve_response_code( $response ) );
1513 + if ( $status < 200 || $status > 299 ) {
1514 + return array(
1515 + 'status' => 200,
1516 + 'body' => '',
1517 + );
1518 + }
1519 +
1520 + return array(
1521 + 'status' => $status,
1522 + 'body' => (string) wp_remote_retrieve_body( $response ),
1523 + );
1524 + }
1525 +
1526 + /**
1527 + * Add stable frontend body class from LASSO_LITE_VERSION (e.g. lasso-lite-v145).
1528 + *
1529 + * @param array<int, string> $classes Body classes.
1530 + * @return array<int, string>
1531 + */
1532 + public function filter_body_class_lasso_lite_version( $classes ) {
1533 + $extra = $this->get_lasso_lite_version_body_class();
1534 + if ( '' !== $extra ) {
1535 + $classes[] = $extra;
1536 + }
1537 + return $classes;
1538 + }
1539 +
1540 + /**
1541 + * CSS-safe class segment: lasso-lite-v{version}.
1542 + *
1543 + * @return string
1544 + */
1545 + private function get_lasso_lite_version_body_class() {
1546 + if ( ! defined( 'LASSO_LITE_VERSION' ) ) {
1547 + return '';
1548 + }
1549 + return 'lasso-lite-v' . sanitize_html_class( str_replace( '.', '-', (string) LASSO_LITE_VERSION ) );
830 1550 }
831 1551 }