| @@ -6,8 +6,10 @@ | ||
| 6 | 6 | */ |
| 7 | 7 | |
| 8 | 8 | namespace LassoLite\Classes; |
| 9 | 9 | |
| 10 | +use LassoLite\Classes\Helper\Url_Format; | |
| 11 | + | |
| 10 | 12 | use LassoLite\Admin\Constant; |
| 11 | 13 | |
| 12 | 14 | use LassoLite\Classes\Affiliate_Link; |
| 13 | 15 | use LassoLite\Classes\Amazon_Api; |
| @@ -214,12 +216,9 @@ | ||
| 214 | 216 | * @param string $url URL. |
| 215 | 217 | * @return bool |
| 216 | 218 | */ |
| 217 | 219 | public static function has_protocol( $url ) { |
| 218 | - if ( strpos( $url, 'http' ) === 0 || strpos( $url, 'https' ) === 0 ) { | |
| 219 | - return true; | |
| 220 | - } | |
| 221 | - return false; | |
| 220 | + return Url_Format::has_protocol( $url ); | |
| 222 | 221 | } |
| 223 | 222 | |
| 224 | 223 | /** |
| 225 | 224 | * Check if Classic Editor plugin is active. |
| @@ -305,42 +304,9 @@ | ||
| 305 | 304 | * |
| 306 | 305 | * @param string $url URL. |
| 307 | 306 | */ |
| 308 | 307 | public static function add_https( $url ) { |
| 309 | - $invalid_url = array( | |
| 310 | - 'https://%20https:/', | |
| 311 | - 'https://xhttps://', | |
| 312 | - 'http:/https://', | |
| 313 | - 'http://https://', | |
| 314 | - 'https://https://', | |
| 315 | - 'https://hhttps://', | |
| 316 | - 'https://]https://', | |
| 317 | - 'https://"https://', | |
| 318 | - '[gift_item link="https://', | |
| 319 | - ']https://', | |
| 320 | - ); | |
| 321 | - $url = trim( $url ); | |
| 322 | - $url = str_replace( $invalid_url, 'https://', $url ); | |
| 323 | - | |
| 324 | - // ? fix mailto in <a> href | |
| 325 | - if ( strpos( $url, 'mailto:' ) !== false || filter_var( $url, FILTER_VALIDATE_EMAIL ) ) { | |
| 326 | - $email = explode( 'mailto:', $url )[1] ?? ''; | |
| 327 | - if ( filter_var( $email, FILTER_VALIDATE_EMAIL ) ) { | |
| 328 | - $url = 'mailto:' . $email; | |
| 329 | - } | |
| 330 | - | |
| 331 | - return $url; | |
| 332 | - } | |
| 333 | - | |
| 334 | - if ( '' === $url || is_null( $url ) || strpos( $url, '[' ) === 0 ) { | |
| 335 | - return $url; | |
| 336 | - } | |
| 337 | - | |
| 338 | - if ( strpos( $url, 'http://' ) !== 0 && strpos( $url, 'https://' ) !== 0 && strpos( $url, '.' ) !== false && '#' !== $url ) { | |
| 339 | - $url = 'https://' . $url; | |
| 340 | - } | |
| 341 | - | |
| 342 | - return $url; | |
| 308 | + return Url_Format::add_https( $url ); | |
| 343 | 309 | } |
| 344 | 310 | |
| 345 | 311 | /** |
| 346 | 312 | * Format URL before sending request |
| @@ -476,9 +442,9 @@ | ||
| 476 | 442 | $setup_amz_tracking_id = boolval( get_option( Enum::SETUP_AMZ_TRACKING_ID ) ) ? 15 : 0; |
| 477 | 443 | $follow_on_twitter = boolval( get_option( Enum::FOLLOW_ON_TWITTER ) ) ? 10 : 0; |
| 478 | 444 | $share_on_twitter = boolval( get_option( Enum::SHARE_ON_TWITTER ) ) ? 10 : 0; |
| 479 | 445 | $leave_a_review = boolval( get_option( Enum::LEAVE_A_REVIEW ) ) ? 5 : 0; |
| 480 | - $is_show_review_note = ! $leave_a_review && $total_links >= 20 && $enable_support && $setup_amz_tracking_id && $follow_on_twitter && $share_on_twitter ? 1 : 0; | |
| 446 | + $is_show_review_note = ! $leave_a_review && $total_links >= 5 && $enable_support && $setup_amz_tracking_id && $follow_on_twitter && $share_on_twitter ? 1 : 0; | |
| 481 | 447 | $progress = $enable_support + $setup_amz_tracking_id + $follow_on_twitter + $share_on_twitter + ( $links * 2 ) + $leave_a_review; |
| 482 | 448 | $progress = $progress ? $progress / 100 : 0; |
| 483 | 449 | $open_modal_add_link = $links < 20 ? 'btn-add-20-links' : ''; |
| 484 | 450 | |
| @@ -503,8 +469,74 @@ | ||
| 503 | 469 | return $data; |
| 504 | 470 | } |
| 505 | 471 | |
| 506 | 472 | /** |
| 473 | + * Whitelist landing-cookie attribution keys for Lite plugin signup (#788). | |
| 474 | + * | |
| 475 | + * @param mixed $raw POST attribution object or JSON string. | |
| 476 | + * @return array|null Sanitized payload or null when no signal. | |
| 477 | + */ | |
| 478 | + public static function sanitize_signup_attribution( $raw ) { | |
| 479 | + $allowed_keys = array( | |
| 480 | + 'url', | |
| 481 | + 'ref', | |
| 482 | + 'utm_source', | |
| 483 | + 'utm_medium', | |
| 484 | + 'utm_campaign', | |
| 485 | + 'utm_content', | |
| 486 | + 'ref_code', | |
| 487 | + 'dt', | |
| 488 | + ); | |
| 489 | + $signal_keys = array( | |
| 490 | + 'utm_source', | |
| 491 | + 'utm_medium', | |
| 492 | + 'utm_campaign', | |
| 493 | + 'utm_content', | |
| 494 | + 'ref_code', | |
| 495 | + ); | |
| 496 | + | |
| 497 | + if ( is_string( $raw ) ) { | |
| 498 | + $raw = json_decode( $raw, true ); | |
| 499 | + } | |
| 500 | + if ( ! is_array( $raw ) || empty( $raw ) ) { | |
| 501 | + return null; | |
| 502 | + } | |
| 503 | + | |
| 504 | + $payload = array(); | |
| 505 | + foreach ( $allowed_keys as $key ) { | |
| 506 | + if ( ! isset( $raw[ $key ] ) || ! is_scalar( $raw[ $key ] ) ) { | |
| 507 | + continue; | |
| 508 | + } | |
| 509 | + $text = trim( (string) $raw[ $key ] ); | |
| 510 | + if ( '' === $text ) { | |
| 511 | + continue; | |
| 512 | + } | |
| 513 | + if ( in_array( $key, array( 'url', 'ref' ), true ) ) { | |
| 514 | + $payload[ $key ] = substr( $text, 0, 2048 ); | |
| 515 | + } else { | |
| 516 | + $payload[ $key ] = substr( $text, 0, 500 ); | |
| 517 | + } | |
| 518 | + } | |
| 519 | + | |
| 520 | + if ( empty( $payload ) ) { | |
| 521 | + return null; | |
| 522 | + } | |
| 523 | + | |
| 524 | + $has_signal = false; | |
| 525 | + foreach ( $signal_keys as $key ) { | |
| 526 | + if ( ! empty( $payload[ $key ] ) ) { | |
| 527 | + $has_signal = true; | |
| 528 | + break; | |
| 529 | + } | |
| 530 | + } | |
| 531 | + if ( ! $has_signal && empty( $payload['url'] ) ) { | |
| 532 | + return null; | |
| 533 | + } | |
| 534 | + | |
| 535 | + return $payload; | |
| 536 | + } | |
| 537 | + | |
| 538 | + /** | |
| 507 | 539 | * Send request |
| 508 | 540 | * |
| 509 | 541 | * @param string $method Method (get or post). Default to get. |
| 510 | 542 | * @param string $url URL. Default to empty. |
| @@ -616,17 +648,9 @@ | ||
| 616 | 648 | * |
| 617 | 649 | * @param string $url URL. |
| 618 | 650 | */ |
| 619 | 651 | public static function validate_url( $url ) { |
| 620 | - if ( ! is_string( $url ) ) { | |
| 621 | - return false; | |
| 622 | - } | |
| 623 | - | |
| 624 | - $url = str_replace( ' ', '%20', $url ); | |
| 625 | - $url = preg_replace( '/[^\00-\255]+/u', '', $url ); | |
| 626 | - | |
| 627 | - return ( ( strpos( $url, 'http://' ) === 0 || strpos( $url, 'https://' ) === 0 ) && | |
| 628 | - filter_var( $url, FILTER_VALIDATE_URL ) !== false ); | |
| 652 | + return Url_Format::validate_url( $url ); | |
| 629 | 653 | } |
| 630 | 654 | |
| 631 | 655 | /** |
| 632 | 656 | * Remove specific parameters from URL |
| @@ -1298,8 +1322,87 @@ | ||
| 1298 | 1322 | return ! empty( ( new Lasso_DB() )->get_import_plugins( true ) ) ? true : false; |
| 1299 | 1323 | } |
| 1300 | 1324 | |
| 1301 | 1325 | /** |
| 1326 | + * Ordered onboarding step ids (tab-item data-step values). | |
| 1327 | + * | |
| 1328 | + * @return string[] | |
| 1329 | + */ | |
| 1330 | + public static function get_onboarding_step_ids() { | |
| 1331 | + return array( 'welcome', 'display', 'amazon', 'connect-lasso', 'import' ); | |
| 1332 | + } | |
| 1333 | + | |
| 1334 | + /** | |
| 1335 | + * @param string $step Step id. | |
| 1336 | + * @return bool | |
| 1337 | + */ | |
| 1338 | + public static function is_valid_onboarding_step( $step ) { | |
| 1339 | + return in_array( $step, self::get_onboarding_step_ids(), true ); | |
| 1340 | + } | |
| 1341 | + | |
| 1342 | + /** | |
| 1343 | + * Last saved onboarding tab for in-progress FTUE. | |
| 1344 | + * | |
| 1345 | + * @param bool $include_import Whether the import step is available for this install. | |
| 1346 | + * @return string | |
| 1347 | + */ | |
| 1348 | + public static function get_onboarding_current_step( $include_import = true ) { | |
| 1349 | + $step = (string) self::get_option( Enum::ONBOARDING_CURRENT_STEP, '' ); | |
| 1350 | + if ( ! self::is_valid_onboarding_step( $step ) ) { | |
| 1351 | + return 'welcome'; | |
| 1352 | + } | |
| 1353 | + if ( 'import' === $step && ! $include_import ) { | |
| 1354 | + return 'connect-lasso'; | |
| 1355 | + } | |
| 1356 | + return $step; | |
| 1357 | + } | |
| 1358 | + | |
| 1359 | + /** | |
| 1360 | + * @param string $step Step id. | |
| 1361 | + * @return bool | |
| 1362 | + */ | |
| 1363 | + public static function save_onboarding_current_step( $step ) { | |
| 1364 | + if ( ! self::is_valid_onboarding_step( $step ) ) { | |
| 1365 | + return false; | |
| 1366 | + } | |
| 1367 | + return self::update_option( Enum::ONBOARDING_CURRENT_STEP, $step ); | |
| 1368 | + } | |
| 1369 | + | |
| 1370 | + /** | |
| 1371 | + * @return bool | |
| 1372 | + */ | |
| 1373 | + public static function clear_onboarding_current_step() { | |
| 1374 | + return self::update_option( Enum::ONBOARDING_CURRENT_STEP, '' ); | |
| 1375 | + } | |
| 1376 | + | |
| 1377 | + /** | |
| 1378 | + * FTUE gate complete: stop redirecting to onboarding and drop saved step. | |
| 1379 | + * | |
| 1380 | + * Cleared after first link creation or an explicit Hub Connect skip. | |
| 1381 | + * | |
| 1382 | + * @return void | |
| 1383 | + */ | |
| 1384 | + public static function mark_onboarding_welcome_complete() { | |
| 1385 | + self::update_option( Enum::IS_VISITED_WELCOME_PAGE, 1 ); | |
| 1386 | + self::clear_onboarding_current_step(); | |
| 1387 | + } | |
| 1388 | + | |
| 1389 | + /** | |
| 1390 | + * Reset FTUE onboarding state for QA (`reset-onboarding=1`). | |
| 1391 | + * | |
| 1392 | + * @return void | |
| 1393 | + */ | |
| 1394 | + public static function reset_onboarding_for_testing() { | |
| 1395 | + self::update_option( Enum::IS_VISITED_WELCOME_PAGE, 0 ); | |
| 1396 | + self::clear_onboarding_current_step(); | |
| 1397 | + update_option( Enum::LASSO_LITE_ACTIVE, 1 ); | |
| 1398 | + self::update_option( Constant::LASSO_ACCOUNT_EMAIL, '' ); | |
| 1399 | + self::update_option( Constant::LASSO_ACCOUNT_API_KEY, '' ); | |
| 1400 | + self::update_option( Constant::LASSO_ACCOUNT_USER_ID, 0 ); | |
| 1401 | + self::update_option( Constant::LASSO_OPTION_IS_CONNECTED_AFFILIATE, '0' ); | |
| 1402 | + } | |
| 1403 | + | |
| 1404 | + /** | |
| 1302 | 1405 | * Get brag icon |
| 1303 | 1406 | * |
| 1304 | 1407 | * @param bool $force_to_show Force to show the brag. Default to false. |
| 1305 | 1408 | */ |
| @@ -1455,8 +1558,32 @@ | ||
| 1455 | 1558 | return true; |
| 1456 | 1559 | } |
| 1457 | 1560 | |
| 1458 | 1561 | /** |
| 1562 | + * CSS custom properties for Lasso display colors (shared admin + block editor iframe). | |
| 1563 | + * | |
| 1564 | + * @param bool $important Append `!important` to each variable value. | |
| 1565 | + * @return string | |
| 1566 | + */ | |
| 1567 | + public static function get_lasso_display_css_variables( $important = false ) { | |
| 1568 | + $settings = Setting::get_settings(); | |
| 1569 | + $suffix = $important ? ' !important' : ''; | |
| 1570 | + | |
| 1571 | + // @codingStandardsIgnoreStart | |
| 1572 | + return ':root{ | |
| 1573 | + --lasso-main: ' . $settings['display_color_main'] . $suffix . '; | |
| 1574 | + --lasso-title: ' . $settings['display_color_title'] . $suffix . '; | |
| 1575 | + --lasso-button: ' . $settings['display_color_button'] . $suffix . '; | |
| 1576 | + --lasso-secondary-button: ' . $settings['display_color_secondary_button'] . $suffix . '; | |
| 1577 | + --lasso-button-text: ' . $settings['display_color_button_text'] . $suffix . '; | |
| 1578 | + --lasso-background: ' . $settings['display_color_background'] . $suffix . '; | |
| 1579 | + --lasso-pros: ' . $settings['display_color_pros'] . $suffix . '; | |
| 1580 | + --lasso-cons: ' . $settings['display_color_cons'] . $suffix . '; | |
| 1581 | + }'; | |
| 1582 | + // @codingStandardsIgnoreEnd | |
| 1583 | + } | |
| 1584 | + | |
| 1585 | + /** | |
| 1459 | 1586 | * Whether show Request Review at the top of the page |
| 1460 | 1587 | */ |
| 1461 | 1588 | public static function show_request_review() { |
| 1462 | 1589 | $link_count = SURL::total(); |
| @@ -1464,10 +1591,11 @@ | ||
| 1464 | 1591 | $lasso_review_allow = self::cast_to_boolean( self::get_option( Constant::LASSO_OPTION_REVIEW_ALLOW, '1' ) ); |
| 1465 | 1592 | $lasso_review_snooze = self::cast_to_boolean( self::get_option( Constant::LASSO_OPTION_REVIEW_SNOOZE, '0' ) ); |
| 1466 | 1593 | $lasso_review_link_count = intval( self::get_option( Constant::LASSO_OPTION_REVIEW_LINK_COUNT, $link_count ) ); |
| 1467 | 1594 | |
| 1468 | - $show = ! $lasso_review_snooze && $link_count >= 20; | |
| 1469 | - $snooze_but_show = $lasso_review_snooze && $link_count - $lasso_review_link_count >= 20; | |
| 1595 | + // Ask after early success (enough links to be real usage), not after a large catalog. | |
| 1596 | + $show = ! $lasso_review_snooze && $link_count >= 5; | |
| 1597 | + $snooze_but_show = $lasso_review_snooze && $link_count - $lasso_review_link_count >= 5; | |
| 1470 | 1598 | |
| 1471 | 1599 | if ( ! $lasso_review_allow ) { |
| 1472 | 1600 | return false; |
| 1473 | 1601 | } |
| @@ -1504,8 +1632,84 @@ | ||
| 1504 | 1632 | return ! $dismissed_fully && ! $updated && ! $has_creators_credentials; |
| 1505 | 1633 | } |
| 1506 | 1634 | |
| 1507 | 1635 | /** |
| 1636 | + * Whether the stored thumbnail is still the default placeholder. | |
| 1637 | + * | |
| 1638 | + * @param string $stored_thumbnail Post meta thumbnail. | |
| 1639 | + * @return bool | |
| 1640 | + */ | |
| 1641 | + private static function uses_default_thumbnail( $stored_thumbnail ) { | |
| 1642 | + $stored_thumbnail = (string) $stored_thumbnail; | |
| 1643 | + | |
| 1644 | + if ( '' === $stored_thumbnail ) { | |
| 1645 | + return true; | |
| 1646 | + } | |
| 1647 | + | |
| 1648 | + if ( false !== strpos( $stored_thumbnail, Constant::DEFAULT_THUMBNAIL ) ) { | |
| 1649 | + return true; | |
| 1650 | + } | |
| 1651 | + | |
| 1652 | + return false !== strpos( $stored_thumbnail, 'lasso-no-thumbnail.jpg' ); | |
| 1653 | + } | |
| 1654 | + | |
| 1655 | + /** | |
| 1656 | + * Whether the footer credentials banner should block the upsell CTA. | |
| 1657 | + * | |
| 1658 | + * The upsell may show after the customer dismisses the banner once, even if the | |
| 1659 | + * banner reappears on a later page load until the second dismiss is recorded. | |
| 1660 | + * | |
| 1661 | + * @return bool | |
| 1662 | + */ | |
| 1663 | + private static function amazon_credentials_banner_blocks_upsell() { | |
| 1664 | + if ( ! self::show_amazon_credentials_notice() ) { | |
| 1665 | + return false; | |
| 1666 | + } | |
| 1667 | + | |
| 1668 | + $dismissed_once = self::cast_to_boolean( | |
| 1669 | + self::get_option( Constant::LASSO_OPTION_AMAZON_CREDENTIALS_NOTICE_DISMISSED, '0' ) | |
| 1670 | + ); | |
| 1671 | + | |
| 1672 | + return ! $dismissed_once; | |
| 1673 | + } | |
| 1674 | + | |
| 1675 | + /** | |
| 1676 | + * Whether to show the Get Amazon Images upsell on URL Details. | |
| 1677 | + * | |
| 1678 | + * @param bool $is_amazon_link Whether the link is an Amazon URL. | |
| 1679 | + * @param string $stored_thumbnail Post meta thumbnail (before Amazon DB enrichment). | |
| 1680 | + * @param bool $is_amazon_configured Whether valid Amazon API credentials exist. | |
| 1681 | + * @return bool | |
| 1682 | + */ | |
| 1683 | + public static function should_show_get_amazon_images_upsell( $is_amazon_link, $stored_thumbnail, $is_amazon_configured ) { | |
| 1684 | + if ( ! $is_amazon_link || $is_amazon_configured ) { | |
| 1685 | + return false; | |
| 1686 | + } | |
| 1687 | + | |
| 1688 | + if ( ! self::uses_default_thumbnail( $stored_thumbnail ) ) { | |
| 1689 | + return false; | |
| 1690 | + } | |
| 1691 | + | |
| 1692 | + return ! self::amazon_credentials_banner_blocks_upsell(); | |
| 1693 | + } | |
| 1694 | + | |
| 1695 | + /** | |
| 1696 | + * Whether the URL Details upsell should render hidden until the credentials banner is dismissed. | |
| 1697 | + * | |
| 1698 | + * @param bool $is_amazon_link Whether the link is an Amazon URL. | |
| 1699 | + * @param string $stored_thumbnail Post meta thumbnail (before Amazon DB enrichment). | |
| 1700 | + * @param bool $is_amazon_configured Whether valid Amazon API credentials exist. | |
| 1701 | + * @return bool | |
| 1702 | + */ | |
| 1703 | + public static function should_defer_get_amazon_images_upsell( $is_amazon_link, $stored_thumbnail, $is_amazon_configured ) { | |
| 1704 | + if ( ! $is_amazon_link || $is_amazon_configured || ! self::uses_default_thumbnail( $stored_thumbnail ) ) { | |
| 1705 | + return false; | |
| 1706 | + } | |
| 1707 | + | |
| 1708 | + return self::amazon_credentials_banner_blocks_upsell(); | |
| 1709 | + } | |
| 1710 | + | |
| 1711 | + /** | |
| 1508 | 1712 | * Get Ajax URL |
| 1509 | 1713 | */ |
| 1510 | 1714 | public static function get_ajax_url() { |
| 1511 | 1715 | return admin_url( 'admin-ajax.php' ); |
| @@ -1541,25 +1745,56 @@ | ||
| 1541 | 1745 | * |
| 1542 | 1746 | * @param string $url URL. |
| 1543 | 1747 | * @param bool $get_res Get response or not. Default to false. |
| 1544 | 1748 | * @param bool $is_lasso_save Is Lasso save data action. Default to false. |
| 1749 | + * @param bool $url_version_param Is add version param to request api url to ignore cache. Default to false. | |
| 1750 | + * @param bool $force_bls Force fetch product from BLS or not. Default to false. | |
| 1751 | + * @param bool $refresh_image Bypass cache and fetch fresh product image/metadata. Default to false. | |
| 1545 | 1752 | */ |
| 1546 | - public static function get_url_status_code_by_broken_link_service( $url, $get_res = false, $is_lasso_save = false ) { | |
| 1753 | + public static function get_url_status_code_by_broken_link_service( $url, $get_res = false, $is_lasso_save = false, $url_version_param = false, $force_bls = false, $refresh_image = false ) { | |
| 1547 | 1754 | $status = 200; |
| 1548 | 1755 | $url = Amazon_Api::get_amazon_product_url( $url, false ); |
| 1549 | 1756 | $url = self::format_url_before_requesting( $url ); |
| 1550 | 1757 | |
| 1551 | 1758 | $headers = self::get_headers(); |
| 1552 | - $data = array( | |
| 1759 | + $query = array( | |
| 1553 | 1760 | 'url' => $url, |
| 1554 | 1761 | ); |
| 1555 | - $res = self::send_request( 'get', Constant::LASSO_LINK . '/link/status/?url=' . $url, array(), $headers ); | |
| 1556 | 1762 | |
| 1763 | + if ( $url_version_param ) { | |
| 1764 | + $query['ver'] = time(); | |
| 1765 | + } | |
| 1766 | + | |
| 1767 | + if ( $force_bls ) { | |
| 1768 | + $query['force_bls'] = 1; | |
| 1769 | + } | |
| 1770 | + | |
| 1771 | + if ( $refresh_image ) { | |
| 1772 | + $query['refresh_image'] = 1; | |
| 1773 | + } | |
| 1774 | + | |
| 1775 | + $request_url = Constant::LASSO_LINK . '/link/status/?' . http_build_query( $query, '', '&', PHP_QUERY_RFC3986 ); | |
| 1776 | + if ( ! $is_lasso_save && defined( 'DOING_CRON' ) && DOING_CRON && ! Cron::should_send_scheduled_data_request( $url ) ) { | |
| 1777 | + return $get_res ? array( | |
| 1778 | + 'status_code' => 200, | |
| 1779 | + 'response' => array(), | |
| 1780 | + ) : 200; | |
| 1781 | + } | |
| 1782 | + Cron::maybe_pace_background_request( $url, $is_lasso_save ); | |
| 1783 | + $res = self::send_request( 'get', $request_url, array(), $headers ); | |
| 1784 | + | |
| 1557 | 1785 | // phpcs:ignore |
| 1558 | - // $res = self::send_request( 'get', LASSO_LINK . '/link/status/?' . $encrypted_base64, array(), $headers ); | |
| 1559 | - $status_temp = intval( $res['response']->status ?? $status ); | |
| 1786 | + // $res = self::send_request( 'get', LASSO_LINK . '/link/status/?' . $encrypted_base64, array(), $headers ); | |
| 1787 | + if ( $get_res ) { | |
| 1788 | + return $res; | |
| 1789 | + } | |
| 1560 | 1790 | |
| 1561 | - return $get_res ? $res : $status_temp; | |
| 1791 | + $bls_response = $res['response'] ?? null; | |
| 1792 | + if ( ! is_object( $bls_response ) ) { | |
| 1793 | + return 500; | |
| 1794 | + } | |
| 1795 | + | |
| 1796 | + return intval( $bls_response->status ?? $status ); | |
| 1562 | 1797 | } |
| 1563 | 1798 | |
| 1564 | 1799 | /** |
| 1565 | 1800 | * Get currency symbol from ISO currency code |
| @@ -1623,12 +1858,15 @@ | ||
| 1623 | 1858 | return $query; |
| 1624 | 1859 | } |
| 1625 | 1860 | |
| 1626 | 1861 | /** |
| 1627 | - * Remove all the script code from the HTML. | |
| 1628 | - * Remove script tags and event attributes (e.g., onload, onsubmit, etc.) | |
| 1862 | + * Sanitize HTML for safe display (formerly regex-based script strip). | |
| 1863 | + * Now delegates to wp_kses_post so event handlers and javascript: URLs are removed. | |
| 1629 | 1864 | * |
| 1630 | - * @param string $html HTML code. | |
| 1865 | + * Falsy input (null, false, empty string) is returned unchanged. | |
| 1866 | + * | |
| 1867 | + * @param string|null|false $html HTML code. | |
| 1868 | + * @return string|null|false Sanitized HTML, or the original falsy value. | |
| 1631 | 1869 | */ |
| 1632 | 1870 | public static function sanitize_script( $html ) { |
| 1633 | 1871 | if ( ! $html ) { |
| 1634 | 1872 | return $html; |
| @@ -1633,15 +1871,9 @@ | ||
| 1633 | 1871 | if ( ! $html ) { |
| 1634 | 1872 | return $html; |
| 1635 | 1873 | } |
| 1636 | 1874 | |
| 1637 | - // ? Remove <script> tags and their variations | |
| 1638 | - $html = preg_replace( '/<script\b[^>]*>.*?<\/script\s*>/is', '', $html ); | |
| 1639 | - | |
| 1640 | - // ? Remove event attributes (e.g., onload, onsubmit, etc.) and their values | |
| 1641 | - $html = preg_replace( '/\s+on\w+\s*=\s*["\'][^"\']*["\']/', ' ', $html ); | |
| 1642 | - | |
| 1643 | - return $html; | |
| 1875 | + return wp_kses_post( (string) $html ); | |
| 1644 | 1876 | } |
| 1645 | 1877 | |
| 1646 | 1878 | /** |
| 1647 | 1879 | * Verify access and nonce, then return wp_send_json_error if unverified. |
| @@ -1678,8 +1910,10 @@ | ||
| 1678 | 1910 | $nonce = $data['nonce'] ?? ''; |
| 1679 | 1911 | if ( false === wp_verify_nonce( $nonce, Constant::LASSO_LITE_NONCE . wp_salt() ) ) { |
| 1680 | 1912 | wp_send_json_error( 'Nonce not verified.' ); |
| 1681 | 1913 | } |
| 1914 | + } catch ( WPAjaxDieStopException $e ) { | |
| 1915 | + throw $e; | |
| 1682 | 1916 | } catch ( \Exception $e ) { |
| 1683 | 1917 | wp_send_json_error( 'Verify access and nonce error.' ); |
| 1684 | 1918 | } |
| 1685 | 1919 | } |
| @@ -1750,9 +1984,9 @@ | ||
| 1750 | 1984 | * |
| 1751 | 1985 | * @return bool |
| 1752 | 1986 | */ |
| 1753 | 1987 | public static function is_wp_elementor_plugin_actived() { |
| 1754 | - return is_plugin_active( 'elementor/elementor.php' ); | |
| 1988 | + return self::get_is_plugin_active( 'elementor/elementor.php' ); | |
| 1755 | 1989 | } |
| 1756 | 1990 | |
| 1757 | 1991 | /** |
| 1758 | 1992 | * FOLLOW ALL REDIRECTS |
| @@ -1810,20 +2044,40 @@ | ||
| 1810 | 2044 | $use_bls = true; |
| 1811 | 2045 | } |
| 1812 | 2046 | |
| 1813 | 2047 | if ( is_wp_error( $res ) || $use_bls || 403 === $status_code ) { |
| 2048 | + $allow_bls = $is_lasso_save | |
| 2049 | + || ! defined( 'DOING_CRON' ) | |
| 2050 | + || ! DOING_CRON | |
| 2051 | + || Cron::should_send_scheduled_data_request( $url ); | |
| 2052 | + if ( ! $allow_bls ) { | |
| 2053 | + $result = $get_page_title ? array( $url, $page_title ) : $url; | |
| 2054 | + Cache_Per_Process::get_instance()->set_cache( $cache_prefix . md5( $url ) . $get_page_title, $result ); | |
| 2055 | + return $result; | |
| 2056 | + } | |
| 1814 | 2057 | $headers = self::get_headers(); |
| 1815 | 2058 | $data = array( |
| 1816 | 2059 | 'url' => $url, |
| 1817 | 2060 | ); |
| 1818 | 2061 | $encrypted_base64 = http_build_query( $data ); |
| 2062 | + Cron::maybe_pace_background_request( $url, $is_lasso_save ); | |
| 1819 | 2063 | $res = self::send_request( 'get', Constant::LASSO_LINK . '/link/final-url/?' . $encrypted_base64, array(), $headers ); |
| 1820 | 2064 | |
| 1821 | - $final_url = $res['response']->finalUrl ?? $url; | |
| 1822 | - $page_title = $res['response']->pageTitle ?? ''; | |
| 2065 | + $bls_response = ( isset( $res['response'] ) && is_object( $res['response'] ) ) ? $res['response'] : null; | |
| 2066 | + $final_url = ( null !== $bls_response ) ? ( $bls_response->finalUrl ?? $url ) : $url; | |
| 2067 | + $page_title = ( null !== $bls_response ) ? ( $bls_response->pageTitle ?? '' ) : ''; | |
| 1823 | 2068 | |
| 2069 | + $bls_status = ( null !== $bls_response && isset( $bls_response->status ) ) ? intval( $bls_response->status ) : 0; | |
| 2070 | + if ( $bls_status ) { | |
| 2071 | + $response_status = $bls_status; | |
| 2072 | + } elseif ( 200 === intval( $res['status_code'] ?? 0 ) ) { | |
| 2073 | + $response_status = 500; | |
| 2074 | + } else { | |
| 2075 | + $response_status = intval( $res['status_code'] ?? 500 ); | |
| 2076 | + } | |
| 2077 | + | |
| 1824 | 2078 | // ? Set the response status code for add new link process |
| 1825 | - Cache_Per_Process::get_instance()->set_cache( Affiliate_Link::ADD_NEW_LINK_RESPONSE_STATUS . md5( $origin_url ), $res['response']->status ?? 200 ); | |
| 2079 | + Cache_Per_Process::get_instance()->set_cache( Affiliate_Link::ADD_NEW_LINK_RESPONSE_STATUS . md5( $origin_url ), $response_status ); | |
| 1826 | 2080 | |
| 1827 | 2081 | $tmp_url = self::get_final_url_from_url_param( $final_url ); |
| 1828 | 2082 | if ( $tmp_url ) { |
| 1829 | 2083 | $page_title = self::get_title_by_url( $tmp_url ); |