PluginProbe
Lasso Lite – Affiliate Link Manager & Product Displays / 156
Lasso Lite – Affiliate Link Manager & Product Displays v156
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 +796 -28 112156 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,9 +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 );
85 + add_filter( 'update_footer', '__return_empty_string', 11 );
74 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 +
75 96 $setting = new Setting();
76 97 if ( $setting->is_surls_page() ) {
77 98 // ? plugin: Pretty Links Pro
78 99 if ( class_exists( 'PrliUpdateController' ) ) {
@@ -102,9 +123,9 @@
102 123 remove_action( 'init', array( $WooZone, 'initThePlugin' ), 5 ); // phpcs:ignore
103 124 }
104 125
105 126 // ? plugin: Client Portal
106 - $lasso_page = $_GET['page'] ?? ''; // phpcs:ignore
127 + $lasso_page = Helper::GET()['page'] ?? ''; // phpcs:ignore
107 128 if ( class_exists( 'CCGClientPortal' ) && Helper::add_prefix_page( Enum::PAGE_DASHBOARD ) === $lasso_page ) {
108 129 global $zohopwp; // phpcs:ignore
109 130 remove_action( 'admin_menu', array( $zohopwp, 'ccgclientportal_admin_menu' ) ); // phpcs:ignore
110 131 }
@@ -156,8 +177,16 @@
156 177
157 178 if ( Helper::is_gravity_perks_plugin_active() ) {
158 179 remove_action( 'admin_print_footer_scripts', array( 'GWPerks', 'welcome_pointer_script' ), 10 ); // phpcs:ignore
159 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' ) );
160 189 }
161 190
162 191
163 192 /**
@@ -191,23 +220,34 @@
191 220 update_option( Enum::SWITCH_TO_NEW_UI, 1 );
192 221 wp_redirect( Page::get_page_url( $dashboard_slug ) ); // phpcs:ignore
193 222 exit;
194 223 } elseif ( 'switch-old-ui' === $get_page ) {
224 + update_option( Enum::LASSO_LITE_ACTIVE, 0 ); // ? fix conflict with L.235
195 225 update_option( Enum::SWITCH_TO_NEW_UI, 0 );
196 226 wp_redirect( Page::get_page_url() ); // phpcs:ignore
197 227 exit;
198 228 }
199 229
200 - // ? Reset onboarding for testing
230 + // ? Reset onboarding for testing (one-shot: strip QA param so step persistence works on reload)
201 231 $reset_onboarding = Helper::GET()[ Enum::RESET_WELCOME_PAGE ] ?? '';
202 232 if ( $reset_onboarding ) {
203 - Helper::update_option( Enum::IS_VISITED_WELCOME_PAGE, 0 );
204 - 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;
205 237 }
206 238
239 + // ? Reset request review for testing
240 + $reset_review = Helper::GET()[ Enum::RESET_REQUEST_REVIEW ] ?? '';
241 + if ( $reset_review ) {
242 + Helper::update_option( Constant::LASSO_OPTION_REVIEW_ALLOW, 1 );
243 + Helper::update_option( Constant::LASSO_OPTION_REVIEW_SNOOZE, 0 );
244 + Helper::update_option( Constant::LASSO_OPTION_REVIEW_LINK_COUNT, 0 );
245 + }
246 +
207 247 // ? The new Lasso Lite active should be redirect to welcome page
208 248 $onboarding_page = Helper::add_prefix_page( Enum::PAGE_ONBOARDING );
209 - $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();
210 250 if ( SIMPLE_URLS_SLUG === $post_type && $onboarding_page !== $get_page && $should_redirect_to_welcome_page ) {
211 251 wp_redirect( Page::get_page_url( $onboarding_page ) ); // phpcs:ignore
212 252 exit;
213 253 } elseif ( $onboarding_page === $get_page && ! $should_redirect_to_welcome_page ) {
@@ -304,14 +344,18 @@
304 344 Helper::enqueue_style( 'bootstrap-select-css', 'bootstrap-select.min.css' );
305 345 Helper::enqueue_style( 'simple-panigation-css', 'simplePagination.css' );
306 346 Helper::enqueue_style( 'select2-css', 'select2.min.css' );
307 347 Helper::enqueue_style( 'lasso-quill', 'quill.snow.css' );
308 - Helper::enqueue_style( 'lasso-live', 'lasso-live.css', array(), 'all', false );
348 + Helper::enqueue_style( 'lasso-lite', 'lasso-lite.css' );
309 349 Helper::enqueue_style( 'lasso-display-modal', 'lasso-display-modal.css' );
310 350 Helper::enqueue_style( 'lasso-dashboard', 'lasso-dashboard.css' );
311 351 Helper::enqueue_style( 'lasso-lite-custom', 'lite-custom.css' );
312 352 }
313 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 +
314 358 if ( $setting->is_setting_display_page() || $setting->is_setting_onboarding_page() ) {
315 359 Helper::enqueue_style( 'spectrum', 'spectrum.min.css' );
316 360 }
317 361
@@ -320,11 +364,17 @@
320 364 Helper::enqueue_style( 'bootstrap-grid-css', 'bootstrap-grid.min.css' );
321 365 Helper::enqueue_style( 'lasso-display-modal', 'lasso-display-modal.css' );
322 366 Helper::enqueue_style( 'simple-pagination', 'simplePagination.css' );
323 367 Helper::enqueue_style( 'lasso-quill', 'quill.snow.css' );
324 - 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' );
325 370 }
326 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 +
327 377 // @codingStandardsIgnoreEnd
328 378 }
329 379
330 380 /**
@@ -333,8 +383,9 @@
333 383 public function add_scripts() {
334 384 if ( ! Helper::is_lite_using_new_ui() ) {
335 385 return;
336 386 }
387 + global $pagenow; // phpcs:ignore
337 388
338 389 $get = Helper::GET(); // phpcs:ignore
339 390 $page = $get['page'] ?? false;
340 391 $setting = new Setting();
@@ -345,24 +396,48 @@
345 396 $data_passed_to_js = array(
346 397 'ajax_url' => admin_url( 'admin-ajax.php' ),
347 398 'site_url' => site_url(),
348 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,
349 403 'rewrite_slug_default' => Enum::REWRITE_SLUG_DEFAULT,
350 404 'simple_urls_slug' => SIMPLE_URLS_SLUG,
351 405 'page_url_details' => Enum::PAGE_URL_DETAILS,
352 406 'setup_progress' => Helper::get_setup_progress_information(),
353 - 'optionsNonce' => wp_create_nonce( 'lasso_settings_save' ),
407 + 'optionsNonce' => wp_create_nonce( Constant::LASSO_LITE_NONCE . wp_salt() ),
354 408 'should_open_support_modal' => $support_enabled,
355 409 'amazon_tracking_id_regex' => Amazon_Api::TRACKING_ID_REGEX,
356 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',
357 414 'block_customize' => Constant::BLOCK_CUSTOMIZE,
415 + 'userId' => Helper::get_option( Constant::LASSO_ACCOUNT_USER_ID ),
358 416 );
417 + $data_passed_to_js['realtime'] = Realtime_Click::get_js_config();
359 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 +
360 425 if ( SIMPLE_URLS_SLUG === $post_type ) {
361 426 wp_dequeue_script( 'up_admin_script' ); // ? fix js conflict with plugin: Download plugin
362 427 }
363 428
364 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 +
365 440 if ( $setting->is_wordpress_post() || $setting->is_surls_page() || $setting->is_custom_post() ) {
366 441 wp_enqueue_script( 'jquery-migrate' ); // ? fix jQuery(...).live is not a function
367 442 wp_enqueue_script( 'jquery' );
368 443 wp_enqueue_script( 'jquery-effects-core' );
@@ -376,8 +451,14 @@
376 451 Helper::enqueue_script( 'lasso-icons-brands', 'brands.min.js', array( 'jquery' ) );
377 452 Helper::enqueue_script( 'circle-progress', 'circle-progress.min.js', array( 'jquery' ) );
378 453
379 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 +
380 461 wp_enqueue_media();
381 462 Helper::enqueue_script( 'moment-js', 'moment.min.js', array( 'jquery' ) );
382 463 Helper::enqueue_script( 'select2-js', 'select2.full.min.js', array( 'jquery' ) );
383 464 Helper::enqueue_script( SIMPLE_URLS_SLUG . '-jq-auto-complete-js', 'jquery-autocomplete.js' );
@@ -391,8 +472,12 @@
391 472 wp_localize_script( 'jquery', 'lassoLiteOptionsData', $data_passed_to_js );
392 473 Helper::enqueue_script( 'lasso-helper', 'lasso-helper.js', array( 'jquery' ) );
393 474 Helper::enqueue_script( 'url-add', 'url-add.js', array( 'jquery' ) );
394 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 + }
395 480
396 481 if ( SIMPLE_URLS_SLUG . '-' . Enum::PAGE_URL_DETAILS === $page ) {
397 482 Helper::enqueue_script( 'url-details', 'url-details.js', array( 'jquery' ) );
398 483 }
@@ -401,14 +486,25 @@
401 486 if ( $setting->is_dashboard_page() ) {
402 487 Helper::enqueue_script( 'dashboard', 'dashboard.js', array( 'jquery' ) );
403 488 }
404 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 +
405 498 if ( $setting->is_setting_display_page() || $setting->is_setting_onboarding_page() ) {
406 499 Helper::enqueue_script( 'spectrum-js', 'spectrum.min.js', array( 'jquery' ) );
407 500 Helper::enqueue_script( 'settings-display-js', 'settings-display.js', array( 'jquery' ) );
408 501 }
409 502
410 - 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() ) {
411 507 Helper::enqueue_script( 'settings-amazon', 'settings-amazon.js', array( 'jquery' ) );
412 508 }
413 509
414 510 if ( $setting->is_import_page() || $setting->is_setting_onboarding_page() ) {
@@ -418,8 +514,9 @@
418 514 if ( $setting->is_setting_onboarding_page() ) {
419 515 Helper::enqueue_script( 'onboarding-js', 'onboarding.js', array( 'jquery' ) );
420 516 Helper::enqueue_script( 'settings-js', 'settings.js', array( 'jquery' ) );
421 517 Helper::enqueue_script( 'settings-display-js', 'settings-display.js', array( 'jquery' ) );
518 + Helper::enqueue_script( 'lasso-signup', 'lasso-signup.js', array( 'jquery' ) );
422 519 }
423 520
424 521 if ( $setting->is_setting_general_page() ) {
425 522 Helper::enqueue_script( 'settings-general', 'settings-general.js', array( 'jquery' ) );
@@ -424,8 +521,12 @@
424 521 if ( $setting->is_setting_general_page() ) {
425 522 Helper::enqueue_script( 'settings-general', 'settings-general.js', array( 'jquery' ) );
426 523 }
427 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 +
428 529 if ( $setting->is_group_detail_page() || $setting->is_group_page() ) {
429 530 Helper::enqueue_script( 'groups', 'groups.js', array( 'jquery' ) );
430 531 }
431 532
@@ -435,9 +536,9 @@
435 536 /**
436 537 * DISPLAYS CSS FOR FRONTEND OF SITE
437 538 */
438 539 public function add_scripts_frontend() {
439 - Helper::enqueue_style( 'lasso-live', 'lasso-live.css', array(), 'all', false );
540 + Helper::enqueue_style( 'lasso-lite', 'lasso-lite.css' );
440 541 }
441 542
442 543 /**
443 544 * DISPLAYS CUSTOM CSS FOR FRONTEND OF SITE
@@ -446,23 +547,10 @@
446 547 if ( ! Helper::is_lite_using_new_ui() ) {
447 548 return;
448 549 }
449 550
450 - $settings = Setting::get_settings();
451 -
452 551 // @codingStandardsIgnoreStart
453 - echo '<style type="text/css">
454 - :root{
455 - --lasso-main: ' . $settings['display_color_main'] . ' !important;
456 - --lasso-title: ' . $settings['display_color_title'] . ' !important;
457 - --lasso-button: ' . $settings['display_color_button'] . ' !important;
458 - --lasso-secondary-button: ' . $settings['display_color_secondary_button'] . ' !important;
459 - --lasso-button-text: ' . $settings['display_color_button_text'] . ' !important;
460 - --lasso-background: ' . $settings['display_color_background'] . ' !important;
461 - --lasso-pros: ' . $settings['display_color_pros'] . ' !important;
462 - --lasso-cons: ' . $settings['display_color_cons'] . ' !important;
463 - }
464 - </style>';
552 + echo '<style type="text/css">' . Helper::get_lasso_display_css_variables( true ) . '</style>';
465 553
466 554 // fix fontawesome js render svg (from other plugins) instead of using css
467 555 echo '
468 556 <script type="text/javascript">
@@ -522,8 +610,20 @@
522 610 'manage_options',
523 611 Constant::LASSO_SUPPORT_URL,
524 612 );
525 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 +
526 626 $new_submenu[100] = array(
527 627 '<b class="green">Upgrade to Pro</b>',
528 628 'manage_options',
529 629 Constant::LASSO_UPGRADE_URL,
@@ -535,13 +635,41 @@
535 635 $submenu[ $menu_key ] = $new_submenu;
536 636 }
537 637
538 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 + /**
539 662 * Load lasso js file in Gutenberg editor
540 663 */
541 664 public function lasso_lite_gutenberg_block() {
542 665 if ( ! Helper::is_lasso_pro_installed() ) {
543 - 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 + );
544 672 Helper::enqueue_script( 'display-add', 'display-add.js', array( 'jquery' ) );
545 673 Helper::enqueue_script( 'url-add', 'url-add.js', array( 'jquery' ) );
546 674 }
547 675 }
@@ -553,10 +681,10 @@
553 681 */
554 682 public function lasso_add_tinymce_plugin( $plugin_array ) {
555 683 if ( ! Helper::is_lasso_pro_plugin_active() ) {
556 684 $lasso_setting = new Setting();
557 - if ( Helper::is_classic_editor_plugin_active() && ( $lasso_setting->is_wordpress_post() || $lasso_setting->is_custom_post() ) ) {
558 - $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
559 687 Helper::enqueue_script( 'display-add', 'display-add.js', array( 'jquery' ) );
560 688 Helper::enqueue_script( 'url-add', 'url-add.js', array( 'jquery' ) );
561 689 }
562 690 }
@@ -587,9 +715,11 @@
587 715
588 716 if ( $lasso_setting->is_wordpress_post() || $lasso_setting->is_custom_post() ) {
589 717 $current_screen = get_current_screen();
590 718 // ? Check to make sure render html only block editor Gutenberg
591 - if ( ( method_exists( $current_screen, 'is_block_editor' ) && $current_screen->is_block_editor() ) || ( function_exists( 'is_gutenberg_page' ) ) && is_gutenberg_page() ) {
719 + if ( ( method_exists( $current_screen, 'is_block_editor' ) && $current_screen->is_block_editor() )
720 + || ( function_exists( 'is_gutenberg_page' ) && is_gutenberg_page() )
721 + ) {
592 722 echo Helper::get_display_modal_html(); // phpcs:ignore
593 723 }
594 724 }
595 725 }
@@ -688,8 +818,11 @@
688 818 /**
689 819 * Prints the templates used in the media manager.
690 820 */
691 821 public function lasso_print_media_templates() {
822 + if ( file_exists( ABSPATH . WPINC . '/media-template.php' ) && ! function_exists( 'wp_print_media_templates' ) ) {
823 + require_once ABSPATH . WPINC . '/media-template.php';
824 + }
692 825 wp_print_media_templates();
693 826 }
694 827
695 828 /**
@@ -778,6 +911,641 @@
778 911 }
779 912 }
780 913 }
781 914 return $results;
915 + }
916 +
917 + /**
918 + * Update the text in the footer
919 + *
920 + * @param string $text Text.
921 + */
922 + public function admin_footer( $text ) {
923 + global $current_screen;
924 +
925 + $setting = new Setting();
926 +
927 + if ( ! empty( $current_screen->id ) && $setting->is_surls_page() ) {
928 + $url = Enum::LASSO_REVIEW_URL;
929 + $text = sprintf(
930 + wp_kses(
931 + 'Enjoying %1$s? Please rate <a href="%2$s" target="_blank" rel="noopener noreferrer">&#9733;&#9733;&#9733;&#9733;&#9733;</a> on <a href="%3$s" target="_blank" rel="noopener">WordPress.org</a> to help us spread the word. Thanks from the Lasso team!',
932 + array(
933 + 'a' => array(
934 + 'href' => array(),
935 + 'target' => array(),
936 + 'rel' => array(),
937 + ),
938 + )
939 + ),
940 + '<strong>Lasso Lite</strong>',
941 + $url,
942 + $url
943 + );
944 + }
945 +
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 ) );
782 1550 }
783 1551 }