| @@ -881,75 +881,8 @@ | ||
| 881 | 881 | return self::$snapchat; |
| 882 | 882 | } |
| 883 | 883 | |
| 884 | 884 | /** |
| 885 | - * Prepare response data for facebook. | |
| 886 | - * | |
| 887 | - * @todo Remove this function in 1.6.18 as it is added in cartflows-tracking file. | |
| 888 | - * @param int $order_id order_id. | |
| 889 | - * @param array $offer_data offer data. | |
| 890 | - * @return void | |
| 891 | - */ | |
| 892 | - public static function send_fb_response_if_enabled( $order_id, $offer_data = array() ) { | |
| 893 | - | |
| 894 | - _deprecated_function( __METHOD__, '1.6.15' ); | |
| 895 | - | |
| 896 | - // Stop Execution if WooCommerce is not installed & don't set the cookie. | |
| 897 | - if ( ! Cartflows_Loader::get_instance()->is_woo_active ) { | |
| 898 | - return; | |
| 899 | - } | |
| 900 | - | |
| 901 | - // @Since 1.6.15 It will only trigger offer purchase event. | |
| 902 | - $fb_settings = self::get_facebook_settings(); | |
| 903 | - if ( 'enable' === $fb_settings['facebook_pixel_tracking'] ) { | |
| 904 | - setcookie( 'wcf_order_details', wp_json_encode( self::prepare_purchase_data_fb_response( $order_id, $offer_data ) ), strtotime( '+1 year' ), '/', COOKIE_DOMAIN, CARTFLOWS_HTTPS, true ); //phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.cookies_setcookie | |
| 905 | - } | |
| 906 | - } | |
| 907 | - | |
| 908 | - /** | |
| 909 | - * Prepare purchase response for facebook purcase event. | |
| 910 | - * | |
| 911 | - * @todo Remove this function in 1.6.18 as it is added in cartflows-tracking file. | |
| 912 | - * | |
| 913 | - * @param integer $order_id order id. | |
| 914 | - * @param array $offer_data offer data. | |
| 915 | - * @return mixed | |
| 916 | - */ | |
| 917 | - public static function prepare_purchase_data_fb_response( $order_id, $offer_data ) { | |
| 918 | - | |
| 919 | - _deprecated_function( __METHOD__, '1.6.15' ); | |
| 920 | - | |
| 921 | - $purchase_data = array(); | |
| 922 | - | |
| 923 | - if ( empty( $offer_data ) ) { | |
| 924 | - return $purchase_data; | |
| 925 | - } | |
| 926 | - | |
| 927 | - if ( ! Cartflows_Loader::get_instance()->is_woo_active ) { | |
| 928 | - return $purchase_data; | |
| 929 | - } | |
| 930 | - | |
| 931 | - $order = wc_get_order( $order_id ); | |
| 932 | - | |
| 933 | - if ( ! $order ) { | |
| 934 | - return $purchase_data; | |
| 935 | - } | |
| 936 | - | |
| 937 | - $purchase_data['content_type'] = 'product'; | |
| 938 | - $purchase_data['currency'] = wcf()->options->get_checkout_meta_value( $order_id, '_order_currency' ); | |
| 939 | - $purchase_data['userAgent'] = wcf()->options->get_checkout_meta_value( $order_id, '_customer_user_agent' ); | |
| 940 | - $purchase_data['plugin'] = 'CartFlows-Offer'; | |
| 941 | - | |
| 942 | - $purchase_data['content_ids'][] = (string) $offer_data['id']; | |
| 943 | - $purchase_data['content_names'][] = $offer_data['name']; | |
| 944 | - $purchase_data['content_category'][] = wp_strip_all_tags( wc_get_product_category_list( $offer_data['id'] ) ); | |
| 945 | - $purchase_data['value'] = $offer_data['total']; | |
| 946 | - $purchase_data['transaction_id'] = $order_id; | |
| 947 | - | |
| 948 | - return $purchase_data; | |
| 949 | - } | |
| 950 | - | |
| 951 | - /** | |
| 952 | 885 | * Get the image url of size. |
| 953 | 886 | * |
| 954 | 887 | * @param int $post_id post id. |
| 955 | 888 | * @param array $key key. |
| @@ -1223,8 +1156,19 @@ | ||
| 1223 | 1156 | |
| 1224 | 1157 | $product = wc_get_product( $product_id ); |
| 1225 | 1158 | } |
| 1226 | 1159 | |
| 1160 | + if ( $product && $product->is_type( 'bundle' ) && method_exists( $product, 'get_bundle_price' ) ) { | |
| 1161 | + /* | |
| 1162 | + * A bundle's own price is only its container base price, which is 0 or empty as soon | |
| 1163 | + * as the bundled items are priced individually — leaving the step showing just a | |
| 1164 | + * currency symbol. Use the bundle's minimum price instead: the "from" price the | |
| 1165 | + * customer would pay, mirroring how a variable product resolves to a variation price | |
| 1166 | + * above. Kept scalar because callers run discount maths on this value. | |
| 1167 | + */ | |
| 1168 | + return $product->get_bundle_price( 'min', false ); | |
| 1169 | + } | |
| 1170 | + | |
| 1227 | 1171 | if ( $product ) { |
| 1228 | 1172 | $custom_price = $product->get_price( 'edit' ); |
| 1229 | 1173 | } |
| 1230 | 1174 | |
| @@ -1747,27 +1691,48 @@ | ||
| 1747 | 1691 | return apply_filters( 'cartflows_show_store_checkout_product_tab', false ); |
| 1748 | 1692 | } |
| 1749 | 1693 | |
| 1750 | 1694 | /** |
| 1751 | - * Function get the CartFlows upgrade to PRO link. | |
| 1695 | + * Common UTM defaults shared across PHP and JS — single source of truth. | |
| 1752 | 1696 | * |
| 1753 | - * @param string $page The page name which needs to be displayed. | |
| 1754 | - * @param string $custom_url The Another URL if wish to send. | |
| 1755 | - * @return string $url The modified URL. | |
| 1697 | + * @return array<string,string> | |
| 1756 | 1698 | */ |
| 1757 | - public static function get_upgrade_to_pro_link( $page = 'cartflows-pricing-plans', $custom_url = '' ) { | |
| 1699 | + public static function get_utm_defaults() { | |
| 1700 | + return array( | |
| 1701 | + 'source' => 'dashboard', | |
| 1702 | + 'medium' => 'free-cartflows', | |
| 1703 | + ); | |
| 1704 | + } | |
| 1758 | 1705 | |
| 1759 | - $base_url = CARTFLOWS_DOMAIN_URL . $page . '/'; | |
| 1760 | - $url = empty( $custom_url ) ? $base_url : esc_url( $custom_url ); | |
| 1706 | + /** | |
| 1707 | + * Build a cartflows.com URL with the common UTM parameters appended. | |
| 1708 | + * Single source of truth for utm_source and utm_medium defaults. | |
| 1709 | + * | |
| 1710 | + * @param string $base_url Destination URL. | |
| 1711 | + * @param array<string,string> $args Optional UTM overrides (utm_source, utm_medium, utm_campaign, utm_content, utm_term). | |
| 1712 | + * @return string The final URL — UTM-stamped, partner-aware, BSF-referer-aware. | |
| 1713 | + */ | |
| 1714 | + public static function get_utm_url( $base_url, $args = array() ) { | |
| 1761 | 1715 | |
| 1762 | 1716 | $partner_id = get_option( 'cartflows_partner_url_param', '' ); |
| 1763 | 1717 | $partner_id = is_string( $partner_id ) ? sanitize_text_field( $partner_id ) : ''; |
| 1764 | 1718 | |
| 1765 | 1719 | if ( ! empty( $partner_id ) ) { |
| 1766 | - return add_query_arg( array( 'cf' => $partner_id ), $url ); | |
| 1720 | + return esc_url( add_query_arg( array( 'cf' => $partner_id ), $base_url ) ); | |
| 1767 | 1721 | } |
| 1768 | 1722 | |
| 1769 | - // Modify the utm_source parameter using the UTM ready link function to include tracking information. | |
| 1723 | + $defaults = self::get_utm_defaults(); | |
| 1724 | + $utm_args = wp_parse_args( | |
| 1725 | + $args, | |
| 1726 | + array( | |
| 1727 | + 'utm_source' => $defaults['source'], | |
| 1728 | + 'utm_medium' => $defaults['medium'], | |
| 1729 | + ) | |
| 1730 | + ); | |
| 1731 | + | |
| 1732 | + $url = add_query_arg( $utm_args, $base_url ); | |
| 1733 | + | |
| 1734 | + // BSF analytics overrides utm_source when a cross-product referer is set; no-op otherwise. | |
| 1770 | 1735 | if ( class_exists( '\BSF_UTM_Analytics' ) && is_callable( '\BSF_UTM_Analytics::get_utm_ready_link' ) ) { |
| 1771 | 1736 | $url = \BSF_UTM_Analytics::get_utm_ready_link( $url, 'cartflows' ); |
| 1772 | 1737 | } |
| 1773 | 1738 | |
| @@ -1774,8 +1739,42 @@ | ||
| 1774 | 1739 | return esc_url( $url ); |
| 1775 | 1740 | } |
| 1776 | 1741 | |
| 1777 | 1742 | /** |
| 1743 | + * Build a CartFlows upgrade-to-pro / pricing URL with UTM params. | |
| 1744 | + * Thin wrapper around get_utm_url() with utm_campaign defaulted to 'go-pro'. | |
| 1745 | + * | |
| 1746 | + * @param string $page Page slug appended to the domain (used when $custom_url is empty). | |
| 1747 | + * @param string $custom_url Optional full URL to use instead of building from $page. | |
| 1748 | + * @param array<string,string> $args Optional UTM overrides. | |
| 1749 | + * @return string The modified URL. | |
| 1750 | + */ | |
| 1751 | + public static function get_upgrade_to_pro_link( $page = 'pricing', $custom_url = '', $args = array() ) { | |
| 1752 | + | |
| 1753 | + $base_url = CARTFLOWS_DOMAIN_URL . $page . '/'; | |
| 1754 | + $url = empty( $custom_url ) ? $base_url : $custom_url; | |
| 1755 | + | |
| 1756 | + $args = wp_parse_args( $args, array( 'utm_campaign' => 'go-pro' ) ); | |
| 1757 | + | |
| 1758 | + return self::get_utm_url( $url, $args ); | |
| 1759 | + } | |
| 1760 | + | |
| 1761 | + /** | |
| 1762 | + * Build a CartFlows knowledgebase / docs URL with UTM params. | |
| 1763 | + * Thin wrapper around get_utm_url() with utm_campaign defaulted to 'docs'. | |
| 1764 | + * | |
| 1765 | + * @param string $base_url Destination docs URL. | |
| 1766 | + * @param array<string,string> $args Optional UTM overrides. | |
| 1767 | + * @return string The modified URL. | |
| 1768 | + */ | |
| 1769 | + public static function get_kb_doc_link( $base_url, $args = array() ) { | |
| 1770 | + | |
| 1771 | + $args = wp_parse_args( $args, array( 'utm_campaign' => 'docs' ) ); | |
| 1772 | + | |
| 1773 | + return self::get_utm_url( $base_url, $args ); | |
| 1774 | + } | |
| 1775 | + | |
| 1776 | + /** | |
| 1778 | 1777 | * Get current page's template |
| 1779 | 1778 | * |
| 1780 | 1779 | * @param int $post_id The current page id. |
| 1781 | 1780 | * @return string |
| @@ -1930,9 +1929,9 @@ | ||
| 1930 | 1929 | * |
| 1931 | 1930 | * @return array<string> Allowed file extensions. |
| 1932 | 1931 | */ |
| 1933 | 1932 | public static function get_allowed_file_extensions() { |
| 1934 | - return array( 'jpg', 'jpeg', 'png', 'gif', 'webp', 'ico', 'pdf', 'mp3', 'm4a', 'wav', 'mp4', 'm4v', 'mov' ); | |
| 1933 | + return array( 'jpg', 'jpeg', 'png', 'gif', 'webp', 'pdf', 'mp3', 'm4a', 'wav', 'mp4', 'm4v', 'mov' ); | |
| 1935 | 1934 | } |
| 1936 | 1935 | |
| 1937 | 1936 | /** |
| 1938 | 1937 | * Sanitize accepted file types input against the master allowlist. |