@automattic/newspack-blocks 4.12.3 → 4.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/dist/carousel/view.asset.php +1 -1
- package/dist/carousel/view.js +3 -3
- package/dist/editor.asset.php +1 -1
- package/dist/editor.js +3 -3
- package/dist/modal.asset.php +1 -1
- package/dist/modal.js +1 -1
- package/dist/modalCheckout-rtl.css +1 -1
- package/dist/modalCheckout.asset.php +1 -1
- package/dist/modalCheckout.css +1 -1
- package/dist/modalCheckout.js +1 -1
- package/includes/class-modal-checkout.php +32 -106
- package/includes/class-newspack-blocks.php +4 -0
- package/includes/modal-checkout/class-checkout-data.php +287 -0
- package/includes/tracking/class-data-events.php +5 -140
- package/newspack-blocks.php +3 -2
- package/package.json +5 -5
- package/src/blocks/checkout-button/view.php +8 -42
- package/src/blocks/donate/frontend/class-newspack-blocks-donate-renderer-base.php +2 -2
- package/src/blocks/donate/frontend/class-newspack-blocks-donate-renderer-frequency-based.php +4 -28
- package/src/blocks/donate/frontend/class-newspack-blocks-donate-renderer-tiers-based.php +5 -17
- package/src/modal-checkout/analytics/ga4/checkout-attempt.js +3 -2
- package/src/modal-checkout/analytics/ga4/checkout-success.js +3 -3
- package/src/modal-checkout/analytics/ga4/dismissed.js +3 -3
- package/src/modal-checkout/analytics/ga4/loaded.js +3 -3
- package/src/modal-checkout/analytics/ga4/pagination.js +3 -2
- package/src/modal-checkout/analytics/ga4/utils/index.js +31 -17
- package/src/modal-checkout/analytics/index.js +1 -1
- package/src/modal-checkout/checkout.scss +2 -1
- package/src/modal-checkout/index.js +1 -1
- package/src/modal-checkout/modal.js +232 -253
- package/src/modal-checkout/templates/thankyou.php +3 -6
- package/src/modal-checkout/utils.js +126 -0
- package/vendor/autoload.php +1 -1
- package/vendor/composer/autoload_real.php +4 -4
- package/vendor/composer/autoload_static.php +2 -2
- package/vendor/composer/installed.php +2 -2
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
namespace Newspack_Blocks;
|
|
9
9
|
|
|
10
|
-
use Newspack_Blocks\
|
|
10
|
+
use Newspack_Blocks\Modal_Checkout\Checkout_Data;
|
|
11
11
|
|
|
12
12
|
defined( 'ABSPATH' ) || exit;
|
|
13
13
|
|
|
@@ -710,8 +710,6 @@ final class Modal_Checkout {
|
|
|
710
710
|
$variation_name = wc_get_formatted_variation( $variation, true );
|
|
711
711
|
$price = $variation->get_price();
|
|
712
712
|
$price_html = $variation->get_price_html();
|
|
713
|
-
$frequency = '';
|
|
714
|
-
$product_type = Data_Events::get_product_type( $product_id );
|
|
715
713
|
|
|
716
714
|
// Use suggested price if NYP is active and set for variation.
|
|
717
715
|
if ( \Newspack_Blocks::can_use_name_your_price() && \WC_Name_Your_Price_Helpers::is_nyp( $variation_id ) ) {
|
|
@@ -722,29 +720,6 @@ final class Modal_Checkout {
|
|
|
722
720
|
}
|
|
723
721
|
}
|
|
724
722
|
|
|
725
|
-
if ( class_exists( '\WC_Subscriptions_Product' ) && \WC_Subscriptions_Product::is_subscription( $variation ) ) {
|
|
726
|
-
$frequency = \WC_Subscriptions_Product::get_period( $variation );
|
|
727
|
-
}
|
|
728
|
-
|
|
729
|
-
$name = sprintf(
|
|
730
|
-
/* translators: 1: variable product name, 2: product variation name */
|
|
731
|
-
__( '%1$s - %2$s', 'newspack-blocks' ),
|
|
732
|
-
$product_name,
|
|
733
|
-
$variation_name
|
|
734
|
-
);
|
|
735
|
-
$product_price_summary = self::get_summary_card_price_string( $name, $price, $frequency );
|
|
736
|
-
$product_data = [
|
|
737
|
-
'amount' => $price,
|
|
738
|
-
'action_type' => 'checkout_button',
|
|
739
|
-
'currency' => function_exists( 'get_woocommerce_currency' ) ? \get_woocommerce_currency() : 'USD',
|
|
740
|
-
'product_price_summary' => $product_price_summary,
|
|
741
|
-
'product_id' => (string) $product_id,
|
|
742
|
-
'product_type' => $product_type,
|
|
743
|
-
'recurrence' => ! empty( $frequency ) ? $frequency : 'once',
|
|
744
|
-
'referrer' => substr( \get_permalink(), strlen( home_url() ) ), // TODO: Is this OK?
|
|
745
|
-
'variation_id' => (string) $variation_id,
|
|
746
|
-
];
|
|
747
|
-
|
|
748
723
|
// Replace nyp price html for variations.
|
|
749
724
|
if ( class_exists( '\WC_Name_Your_Price_Helpers' ) && \WC_Name_Your_Price_Helpers::is_nyp( $variation->get_id() ) ) {
|
|
750
725
|
$price_html = str_replace( ':', '', $price_html );
|
|
@@ -757,7 +732,7 @@ final class Modal_Checkout {
|
|
|
757
732
|
<span class="price"><?php echo $price_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></span>
|
|
758
733
|
</div>
|
|
759
734
|
<div class="variation"><?php echo esc_html( $variation_name ); ?></div>
|
|
760
|
-
<form data-
|
|
735
|
+
<form data-checkout="<?php echo esc_attr( wp_json_encode( Checkout_Data::get_checkout_data( $variation ) ) ); ?>">
|
|
761
736
|
<input type="hidden" name="newspack_checkout" value="1" />
|
|
762
737
|
<button type="submit" class="<?php echo esc_attr( "{$class_prefix}__button {$class_prefix}__button--primary" ); ?> newspack-modal-checkout-variation-selection"><?php echo esc_html( self::get_modal_checkout_labels( 'checkout_confirm_variation' ) ); ?></button>
|
|
763
738
|
</form>
|
|
@@ -1025,6 +1000,7 @@ final class Modal_Checkout {
|
|
|
1025
1000
|
'newspack_class_prefix' => self::get_class_prefix(),
|
|
1026
1001
|
'is_registration_required' => self::is_registration_required(),
|
|
1027
1002
|
'has_unsupported_payment_gateway' => self::has_unsupported_payment_gateway(),
|
|
1003
|
+
'checkout_url' => remove_query_arg( 'my_account_checkout', add_query_arg( 'modal_checkout', '1', wc_get_checkout_url() ) ),
|
|
1028
1004
|
'labels' => [
|
|
1029
1005
|
'auth_modal_title' => self::get_modal_checkout_labels( 'auth_modal_title' ),
|
|
1030
1006
|
'checkout_modal_title' => self::get_modal_checkout_labels( 'checkout_modal_title' ),
|
|
@@ -1111,29 +1087,23 @@ final class Modal_Checkout {
|
|
|
1111
1087
|
* Get after success button params.
|
|
1112
1088
|
*/
|
|
1113
1089
|
private static function get_after_success_params() {
|
|
1114
|
-
|
|
1090
|
+
$request_params = $_REQUEST; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
|
1115
1091
|
if ( self::is_express_checkout() ) {
|
|
1092
|
+
$request_params = [];
|
|
1116
1093
|
$referrer = isset( $_SERVER['HTTP_REFERER'] ) ? \esc_url_raw( \wp_unslash( $_SERVER['HTTP_REFERER'] ) ) : false; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
|
|
1117
1094
|
if ( $referrer ) {
|
|
1118
1095
|
$referrer_query = \wp_parse_url( $referrer, PHP_URL_QUERY );
|
|
1119
|
-
\wp_parse_str( $referrer_query, $
|
|
1120
|
-
return array_filter(
|
|
1121
|
-
[
|
|
1122
|
-
'after_success_behavior' => isset( $referrer_query_params['after_success_behavior'] ) ? sanitize_text_field( wp_unslash( $referrer_query_params['after_success_behavior'] ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
|
1123
|
-
'after_success_url' => isset( $referrer_query_params['after_success_url'] ) ? sanitize_url( wp_unslash( $referrer_query_params['after_success_url'] ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
|
1124
|
-
'after_success_button_label' => isset( $referrer_query_params['after_success_button_label'] ) ? sanitize_text_field( wp_unslash( $referrer_query_params['after_success_button_label'] ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
|
1125
|
-
]
|
|
1126
|
-
);
|
|
1096
|
+
\wp_parse_str( $referrer_query, $request_params );
|
|
1127
1097
|
}
|
|
1128
|
-
} else {
|
|
1129
|
-
return array_filter(
|
|
1130
|
-
[
|
|
1131
|
-
'after_success_behavior' => isset( $_REQUEST['after_success_behavior'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['after_success_behavior'] ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
|
1132
|
-
'after_success_url' => isset( $_REQUEST['after_success_url'] ) ? sanitize_url( wp_unslash( $_REQUEST['after_success_url'] ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
|
1133
|
-
'after_success_button_label' => isset( $_REQUEST['after_success_button_label'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['after_success_button_label'] ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
|
1134
|
-
]
|
|
1135
|
-
);
|
|
1136
1098
|
}
|
|
1099
|
+
return array_filter(
|
|
1100
|
+
[
|
|
1101
|
+
'after_success_behavior' => isset( $request_params['after_success_behavior'] ) ? sanitize_text_field( wp_unslash( $request_params['after_success_behavior'] ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
|
1102
|
+
'after_success_url' => isset( $request_params['after_success_url'] ) ? sanitize_url( wp_unslash( $request_params['after_success_url'] ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
|
1103
|
+
'after_success_button_label' => isset( $request_params['after_success_button_label'] ) ? sanitize_text_field( wp_unslash( $request_params['after_success_button_label'] ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
|
1104
|
+
'action_type' => isset( $request_params['action_type'] ) ? sanitize_text_field( wp_unslash( $request_params['action_type'] ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
|
1105
|
+
]
|
|
1106
|
+
);
|
|
1137
1107
|
}
|
|
1138
1108
|
|
|
1139
1109
|
/**
|
|
@@ -1538,16 +1508,7 @@ final class Modal_Checkout {
|
|
|
1538
1508
|
*/
|
|
1539
1509
|
public static function pass_url_param_on_redirect( $location ) {
|
|
1540
1510
|
if ( self::is_modal_checkout() ) {
|
|
1541
|
-
$
|
|
1542
|
-
$newspack_popup_id = filter_input( INPUT_GET, 'newspack_popup_id', FILTER_SANITIZE_NUMBER_INT );
|
|
1543
|
-
$gate_post_id = filter_input( INPUT_GET, 'memberships_content_gate', FILTER_SANITIZE_NUMBER_INT );
|
|
1544
|
-
if ( $newspack_popup_id ) {
|
|
1545
|
-
$params['newspack_popup_id'] = $newspack_popup_id;
|
|
1546
|
-
}
|
|
1547
|
-
if ( $gate_post_id ) {
|
|
1548
|
-
$params['memberships_content_gate'] = $gate_post_id;
|
|
1549
|
-
}
|
|
1550
|
-
$location = \add_query_arg( $params, $location );
|
|
1511
|
+
$location = \add_query_arg( [ 'modal_checkout' => 1 ], $location );
|
|
1551
1512
|
}
|
|
1552
1513
|
return $location;
|
|
1553
1514
|
}
|
|
@@ -1707,29 +1668,28 @@ final class Modal_Checkout {
|
|
|
1707
1668
|
if ( 1 !== $cart->get_cart_contents_count() ) {
|
|
1708
1669
|
return;
|
|
1709
1670
|
}
|
|
1671
|
+
$cart_item_key = array_key_first( $cart->get_cart() );
|
|
1672
|
+
$cart_item = $cart->get_cart_item( $cart_item_key );
|
|
1673
|
+
$product_id = $cart_item['variation_id'] ? $cart_item['variation_id'] : $cart_item['product_id'];
|
|
1710
1674
|
$class_prefix = self::get_class_prefix();
|
|
1711
1675
|
?>
|
|
1712
1676
|
<div class="<?php echo esc_attr( "order-details-summary {$class_prefix}__box {$class_prefix}__box--text-center" ); ?>">
|
|
1713
1677
|
<?php
|
|
1714
1678
|
// phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- WooCommerce hooks.
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
</p>
|
|
1730
|
-
<?php
|
|
1731
|
-
endif;
|
|
1732
|
-
endforeach;
|
|
1679
|
+
$_product = apply_filters( 'woocommerce_cart_item_product', $cart_item['data'], $cart_item, $cart_item_key );
|
|
1680
|
+
if ( $_product && $_product->exists() && $cart_item['quantity'] > 0 && apply_filters( 'woocommerce_checkout_cart_item_visible', true, $cart_item, $cart_item_key ) ) :
|
|
1681
|
+
?>
|
|
1682
|
+
<p id="modal-checkout-product-details" data-checkout='<?php echo wp_json_encode( Checkout_Data::get_checkout_data( $cart ) ); ?>'>
|
|
1683
|
+
<strong>
|
|
1684
|
+
<?php
|
|
1685
|
+
echo apply_filters( 'woocommerce_cart_item_name', $_product->get_name(), $cart_item, $cart_item_key ) . ': '; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
|
1686
|
+
echo wc_get_formatted_cart_item_data( $cart_item ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
|
1687
|
+
?>
|
|
1688
|
+
<?php echo apply_filters( 'woocommerce_cart_item_subtotal', $cart->get_product_subtotal( $_product, $cart_item['quantity'] ), $cart_item, $cart_item_key ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
|
1689
|
+
</strong>
|
|
1690
|
+
</p>
|
|
1691
|
+
<?php
|
|
1692
|
+
endif;
|
|
1733
1693
|
// phpcs:enable
|
|
1734
1694
|
?>
|
|
1735
1695
|
</div>
|
|
@@ -2080,40 +2040,6 @@ final class Modal_Checkout {
|
|
|
2080
2040
|
return self::$modal_checkout_labels[ $key ] ?? '';
|
|
2081
2041
|
}
|
|
2082
2042
|
|
|
2083
|
-
/**
|
|
2084
|
-
* Get price string for the price summary card to render in auth flow.
|
|
2085
|
-
*
|
|
2086
|
-
* @param string $name The name.
|
|
2087
|
-
* @param string $price The price. Optional. If not provided, the price string will contain 0.
|
|
2088
|
-
* @param string $frequency The frequency. Optional. If not provided, the price will be treated as a one-time payment.
|
|
2089
|
-
*
|
|
2090
|
-
* @return string The price string.
|
|
2091
|
-
*/
|
|
2092
|
-
public static function get_summary_card_price_string( $name, $price = '', $frequency = '' ) {
|
|
2093
|
-
if ( ! $price ) {
|
|
2094
|
-
$price = '0';
|
|
2095
|
-
}
|
|
2096
|
-
|
|
2097
|
-
if ( function_exists( 'wcs_price_string' ) && function_exists( 'wc_price' ) ) {
|
|
2098
|
-
if ( $frequency && $frequency !== 'once' ) {
|
|
2099
|
-
$price = wp_strip_all_tags(
|
|
2100
|
-
wcs_price_string(
|
|
2101
|
-
[
|
|
2102
|
-
'recurring_amount' => $price,
|
|
2103
|
-
'subscription_period' => $frequency,
|
|
2104
|
-
'use_per_slash' => true,
|
|
2105
|
-
]
|
|
2106
|
-
)
|
|
2107
|
-
);
|
|
2108
|
-
} else {
|
|
2109
|
-
$price = wp_strip_all_tags( wc_price( $price ) );
|
|
2110
|
-
}
|
|
2111
|
-
}
|
|
2112
|
-
|
|
2113
|
-
// translators: 1 is the name of the item. 2 is the price of the item.
|
|
2114
|
-
return sprintf( __( '%1$s: %2$s', 'newspack-blocks' ), $name, $price );
|
|
2115
|
-
}
|
|
2116
|
-
|
|
2117
2043
|
/**
|
|
2118
2044
|
* Set the checkout registration flag to WC session.
|
|
2119
2045
|
*/
|
|
@@ -1504,6 +1504,10 @@ class Newspack_Blocks {
|
|
|
1504
1504
|
$currency_symbol = function_exists( 'get_woocommerce_currency_symbol' ) ? \get_woocommerce_currency_symbol() : '$';
|
|
1505
1505
|
$wc_formatted_amount = '<span class="woocommerce-Price-amount amount"><bdi><span class="woocommerce-Price-currencySymbol">' . $currency_symbol . '</span>AMOUNT_PLACEHOLDER</bdi></span> FREQUENCY_PLACEHOLDER';
|
|
1506
1506
|
} else {
|
|
1507
|
+
// If it's a float but with no decimal value, treat it as an int.
|
|
1508
|
+
if ( is_float( $amount ) && floor( $amount ) == $amount ) {
|
|
1509
|
+
$amount = (int) $amount;
|
|
1510
|
+
}
|
|
1507
1511
|
// Format the amount with currency symbol and separators.
|
|
1508
1512
|
$amount_string = \wc_price(
|
|
1509
1513
|
$amount,
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
/**
|
|
3
|
+
* Newspack Blocks Modal Checkout Data.
|
|
4
|
+
*
|
|
5
|
+
* @package Newspack
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
namespace Newspack_Blocks\Modal_Checkout;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Checkout Data Class.
|
|
12
|
+
*/
|
|
13
|
+
final class Checkout_Data {
|
|
14
|
+
/**
|
|
15
|
+
* Get price string for the price summary card to render in auth flow.
|
|
16
|
+
*
|
|
17
|
+
* @param string $name The name.
|
|
18
|
+
* @param string $price The price. Optional. If not provided, the price string will contain 0.
|
|
19
|
+
* @param string $frequency The frequency. Optional. If not provided, the price will be treated as a one-time payment.
|
|
20
|
+
*
|
|
21
|
+
* @return string The price string.
|
|
22
|
+
*/
|
|
23
|
+
public static function get_price_summary( $name, $price = '', $frequency = '' ) {
|
|
24
|
+
if ( ! $price ) {
|
|
25
|
+
$price = '0';
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if ( function_exists( 'wcs_price_string' ) && function_exists( 'wc_price' ) ) {
|
|
29
|
+
if ( $frequency && $frequency !== 'once' ) {
|
|
30
|
+
$price = wp_strip_all_tags(
|
|
31
|
+
wcs_price_string(
|
|
32
|
+
[
|
|
33
|
+
'recurring_amount' => $price,
|
|
34
|
+
'subscription_period' => $frequency,
|
|
35
|
+
'use_per_slash' => true,
|
|
36
|
+
]
|
|
37
|
+
)
|
|
38
|
+
);
|
|
39
|
+
} else {
|
|
40
|
+
$price = wp_strip_all_tags( wc_price( $price ) );
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// translators: 1 is the name of the item. 2 is the price of the item.
|
|
45
|
+
return sprintf( __( '%1$s: %2$s', 'newspack-blocks' ), $name, $price );
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Returns whether a product is a one time purchase, or recurring and when.
|
|
50
|
+
*
|
|
51
|
+
* @param string $product_id Product's ID.
|
|
52
|
+
*/
|
|
53
|
+
public static function get_purchase_recurrence( $product_id ) {
|
|
54
|
+
$recurrence = get_post_meta( $product_id, '_subscription_period', true );
|
|
55
|
+
if ( empty( $recurrence ) ) {
|
|
56
|
+
$recurrence = 'once';
|
|
57
|
+
}
|
|
58
|
+
return $recurrence;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Returns whether a product ID is associated with a membership.
|
|
63
|
+
*
|
|
64
|
+
* @param string $product_id Product's ID.
|
|
65
|
+
*/
|
|
66
|
+
public static function is_membership_product( $product_id ) {
|
|
67
|
+
if ( ! function_exists( 'wc_memberships_get_membership_plans' ) ) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
$membership_plans = wc_memberships_get_membership_plans();
|
|
71
|
+
$plans = [];
|
|
72
|
+
|
|
73
|
+
foreach ( $membership_plans as $plan ) {
|
|
74
|
+
$subscription_plan = new \WC_Memberships_Integration_Subscriptions_Membership_Plan( $plan->get_id() );
|
|
75
|
+
$required_products = $subscription_plan->get_subscription_product_ids();
|
|
76
|
+
if ( in_array( $product_id, $required_products ) ) {
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Returns the product type: product, subscription, donation, or membership.
|
|
86
|
+
*
|
|
87
|
+
* @param string $product_id Product's ID.
|
|
88
|
+
*/
|
|
89
|
+
public static function get_product_type( $product_id ) {
|
|
90
|
+
$product_type = 'product';
|
|
91
|
+
$recurrence = self::get_purchase_recurrence( $product_id );
|
|
92
|
+
|
|
93
|
+
// Check if it's a subscription product.
|
|
94
|
+
if ( 'once' !== $recurrence ) {
|
|
95
|
+
$product_type = 'subscription';
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Check if it's a membership product.
|
|
99
|
+
if ( self::is_membership_product( $product_id ) ) {
|
|
100
|
+
$product_type = 'membership';
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Check if it's a donation product.
|
|
104
|
+
if ( method_exists( 'Newspack\Donations', 'is_donation_product' ) ) {
|
|
105
|
+
if ( \Newspack\Donations::is_donation_product( $product_id ) ) {
|
|
106
|
+
$product_type = 'donation';
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return $product_type;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Returns the action type: checkout_button or donation.
|
|
115
|
+
*
|
|
116
|
+
* @param string $product_id Product's ID.
|
|
117
|
+
*/
|
|
118
|
+
public static function get_action_type( $product_id ) {
|
|
119
|
+
$action_type = 'checkout_button';
|
|
120
|
+
// Check if it's a donation product, and update action_type, product_type.
|
|
121
|
+
if ( method_exists( 'Newspack\Donations', 'is_donation_product' ) ) {
|
|
122
|
+
if ( \Newspack\Donations::is_donation_product( $product_id ) ) {
|
|
123
|
+
$action_type = 'donation';
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return $action_type;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Get donate product checkout data.
|
|
131
|
+
*
|
|
132
|
+
* @param string $frequency The frequency.
|
|
133
|
+
* @param int $amount The amount.
|
|
134
|
+
*
|
|
135
|
+
* @return array
|
|
136
|
+
*/
|
|
137
|
+
public static function get_donation_checkout_data( $frequency, $amount = null ) {
|
|
138
|
+
if ( ! method_exists( 'Newspack\Donations', 'get_donation_product' ) ) {
|
|
139
|
+
return [];
|
|
140
|
+
}
|
|
141
|
+
$product_id = \Newspack\Donations::get_donation_product( $frequency );
|
|
142
|
+
if ( ! $product_id ) {
|
|
143
|
+
return [];
|
|
144
|
+
}
|
|
145
|
+
$product = wc_get_product( $product_id );
|
|
146
|
+
if ( ! $product ) {
|
|
147
|
+
return [];
|
|
148
|
+
}
|
|
149
|
+
$data = self::get_checkout_data( $product );
|
|
150
|
+
if ( $amount ) {
|
|
151
|
+
$data['amount'] = $amount;
|
|
152
|
+
}
|
|
153
|
+
return $data;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Returns checkout data given a product, product variation, cart or order object.
|
|
158
|
+
*
|
|
159
|
+
* @param \WC_Product|\WC_Product_Variation|\WC_Cart|\WC_Order $source Product, product variation, cart or order object.
|
|
160
|
+
*
|
|
161
|
+
* @return array
|
|
162
|
+
*/
|
|
163
|
+
public static function get_checkout_data( $source ) {
|
|
164
|
+
$data = [];
|
|
165
|
+
if ( empty( $source ) ) {
|
|
166
|
+
return $data;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
$cart_item = null;
|
|
170
|
+
$order = null;
|
|
171
|
+
$referrer = '';
|
|
172
|
+
$variation_id = null;
|
|
173
|
+
|
|
174
|
+
if ( $source instanceof \WC_Product_Variation ) {
|
|
175
|
+
$product_id = $source->get_parent_id();
|
|
176
|
+
$variation_id = $source->get_id();
|
|
177
|
+
$amount = $source->get_price();
|
|
178
|
+
} elseif ( $source instanceof \WC_Product ) {
|
|
179
|
+
$product_id = $source->get_id();
|
|
180
|
+
if ( $source->get_parent_id() ) {
|
|
181
|
+
$product_id = $source->get_parent_id();
|
|
182
|
+
$variation_id = $source->get_id();
|
|
183
|
+
}
|
|
184
|
+
$amount = $source->get_price();
|
|
185
|
+
} elseif ( $source instanceof \WC_Cart ) {
|
|
186
|
+
$cart_items = $source->get_cart();
|
|
187
|
+
$cart_item = reset( $cart_items ); // Use only the first item in the cart.
|
|
188
|
+
$product_id = $cart_item['product_id'];
|
|
189
|
+
$variation_id = $cart_item['variation_id'];
|
|
190
|
+
$amount = $cart_item['data']->get_price();
|
|
191
|
+
$referrer = $cart_item['referer'] ?? '';
|
|
192
|
+
} elseif ( $source instanceof \WC_Order ) {
|
|
193
|
+
$order = $source;
|
|
194
|
+
$order_items = $order->get_items();
|
|
195
|
+
$order_item = reset( $order_items ); // Use only the first item in the order.
|
|
196
|
+
$product_id = $order_item->get_product_id();
|
|
197
|
+
$variation_id = $order_item->get_variation_id();
|
|
198
|
+
$amount = $order_item->get_subtotal();
|
|
199
|
+
$referrer = $order->get_meta( '_newspack_referer' );
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// If we have no referrer, set it to the current path.
|
|
203
|
+
if ( ! $referrer ) {
|
|
204
|
+
global $wp;
|
|
205
|
+
$referrer = $wp->request;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
$product_type = self::get_product_type( $product_id );
|
|
209
|
+
$recurrence = self::get_purchase_recurrence( $product_id );
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Price summary name.
|
|
213
|
+
*/
|
|
214
|
+
if ( 'donation' === $product_type ) {
|
|
215
|
+
$name = __( 'Donate', 'newspack-blocks' );
|
|
216
|
+
} elseif ( $variation_id ) {
|
|
217
|
+
$variation = wc_get_product( $variation_id );
|
|
218
|
+
$name = $variation->get_name();
|
|
219
|
+
} else {
|
|
220
|
+
$product = wc_get_product( $product_id );
|
|
221
|
+
$name = $product->get_name();
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
$data = [
|
|
225
|
+
'amount' => $amount,
|
|
226
|
+
'action_type' => self::get_action_type( $product_id ),
|
|
227
|
+
'currency' => function_exists( 'get_woocommerce_currency' ) ? \get_woocommerce_currency() : 'USD',
|
|
228
|
+
'product_id' => strval( $product_id ? $product_id : '' ),
|
|
229
|
+
'product_type' => $product_type,
|
|
230
|
+
'price_summary' => self::get_price_summary( $name, $amount, $recurrence ),
|
|
231
|
+
'summary_template' => self::get_price_summary( $name, '{{PRICE}}', $recurrence ),
|
|
232
|
+
'referrer' => $referrer ? str_replace( home_url(), '', $referrer ) : '', // Keeps format consistent for Homepage with Donate and Checkout Button blocks.
|
|
233
|
+
'recurrence' => $recurrence,
|
|
234
|
+
'variation_id' => strval( $variation_id ? $variation_id : '' ),
|
|
235
|
+
];
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Order specific data.
|
|
239
|
+
*/
|
|
240
|
+
if ( $order ) {
|
|
241
|
+
$data['order_id'] = $order->get_id();
|
|
242
|
+
if ( in_array( $product_type, [ 'subscription', 'membership' ], true ) ) {
|
|
243
|
+
$subscription_renewal = $order->get_meta( '_subscription_renewal' );
|
|
244
|
+
if ( $subscription_renewal ) {
|
|
245
|
+
$data['subscription_renewal'] = $subscription_renewal;
|
|
246
|
+
}
|
|
247
|
+
if ( function_exists( 'wcs_get_subscriptions_for_order' ) ) {
|
|
248
|
+
$subscriptions = wcs_get_subscriptions_for_order( $order );
|
|
249
|
+
if ( ! empty( $subscriptions ) ) {
|
|
250
|
+
$data['subscription_ids'] = array_values(
|
|
251
|
+
array_map(
|
|
252
|
+
function( $subscription ) {
|
|
253
|
+
return $subscription->get_id();
|
|
254
|
+
},
|
|
255
|
+
$subscriptions
|
|
256
|
+
)
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Gate and popup data.
|
|
265
|
+
*/
|
|
266
|
+
$gate_post_id = null;
|
|
267
|
+
$newspack_popup_id = null;
|
|
268
|
+
if ( $order ) {
|
|
269
|
+
$gate_post_id = $order->get_meta( '_memberships_content_gate' );
|
|
270
|
+
$newspack_popup_id = $order->get_meta( '_newspack_popup_id' );
|
|
271
|
+
} elseif ( $cart_item ) {
|
|
272
|
+
$gate_post_id = $cart_item['memberships_content_gate'] ?? null;
|
|
273
|
+
$newspack_popup_id = $cart_item['newspack_popup_id'] ?? null;
|
|
274
|
+
} else {
|
|
275
|
+
$gate_post_id = filter_input( INPUT_GET, 'memberships_content_gate', FILTER_SANITIZE_NUMBER_INT );
|
|
276
|
+
$newspack_popup_id = filter_input( INPUT_GET, 'newspack_popup_id', FILTER_SANITIZE_NUMBER_INT );
|
|
277
|
+
}
|
|
278
|
+
if ( $gate_post_id ) {
|
|
279
|
+
$data['gate_post_id'] = $gate_post_id;
|
|
280
|
+
}
|
|
281
|
+
if ( $newspack_popup_id ) {
|
|
282
|
+
$data['newspack_popup_id'] = $newspack_popup_id;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
return $data;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
|
|
8
8
|
namespace Newspack_Blocks\Tracking;
|
|
9
9
|
|
|
10
|
+
use Newspack_Blocks\Modal_Checkout\Checkout_Data;
|
|
11
|
+
|
|
10
12
|
/**
|
|
11
13
|
* Tracking Data Events Class.
|
|
12
14
|
*/
|
|
@@ -47,143 +49,6 @@ final class Data_Events {
|
|
|
47
49
|
);
|
|
48
50
|
}
|
|
49
51
|
|
|
50
|
-
/**
|
|
51
|
-
* Returns whether a product is a one time purchase, or recurring and when.
|
|
52
|
-
*
|
|
53
|
-
* @param string $product_id Product's ID.
|
|
54
|
-
*/
|
|
55
|
-
public static function get_purchase_recurrence( $product_id ) {
|
|
56
|
-
$recurrence = get_post_meta( $product_id, '_subscription_period', true );
|
|
57
|
-
if ( empty( $recurrence ) ) {
|
|
58
|
-
$recurrence = 'once';
|
|
59
|
-
}
|
|
60
|
-
return $recurrence;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Returns whether a product ID is associated with a membership.
|
|
65
|
-
*
|
|
66
|
-
* @param string $product_id Product's ID.
|
|
67
|
-
*/
|
|
68
|
-
public static function is_membership_product( $product_id ) {
|
|
69
|
-
if ( ! function_exists( 'wc_memberships_get_membership_plans' ) ) {
|
|
70
|
-
return false;
|
|
71
|
-
}
|
|
72
|
-
$membership_plans = wc_memberships_get_membership_plans();
|
|
73
|
-
$plans = [];
|
|
74
|
-
|
|
75
|
-
foreach ( $membership_plans as $plan ) {
|
|
76
|
-
$subscription_plan = new \WC_Memberships_Integration_Subscriptions_Membership_Plan( $plan->get_id() );
|
|
77
|
-
$required_products = $subscription_plan->get_subscription_product_ids();
|
|
78
|
-
if ( in_array( $product_id, $required_products ) ) {
|
|
79
|
-
return true;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
return false;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Returns the product type: product, subscription, donation, or membership.
|
|
88
|
-
* TODOGA4: move this check & related functions into a more central location, and update based on final decision for product types.
|
|
89
|
-
*
|
|
90
|
-
* @param string $product_id Product's ID.
|
|
91
|
-
*/
|
|
92
|
-
public static function get_product_type( $product_id ) {
|
|
93
|
-
$product_type = 'product';
|
|
94
|
-
$recurrence = self::get_purchase_recurrence( $product_id );
|
|
95
|
-
|
|
96
|
-
// Check if it's a subscription product.
|
|
97
|
-
if ( 'once' !== $recurrence ) {
|
|
98
|
-
$product_type = 'subscription';
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// Check if it's a membership product.
|
|
102
|
-
if ( self::is_membership_product( $product_id ) ) {
|
|
103
|
-
$product_type = 'membership';
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// Check if it's a donation product.
|
|
107
|
-
if ( method_exists( 'Newspack\Donations', 'is_donation_product' ) ) {
|
|
108
|
-
if ( \Newspack\Donations::is_donation_product( $product_id ) ) {
|
|
109
|
-
$product_type = 'donation';
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
return $product_type;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Returns the action type: checkout_button or donation.
|
|
118
|
-
*
|
|
119
|
-
* @param string $product_id Product's ID.
|
|
120
|
-
*/
|
|
121
|
-
public static function get_action_type( $product_id ) {
|
|
122
|
-
$action_type = 'checkout_button';
|
|
123
|
-
// Check if it's a donation product, and update action_type, product_type.
|
|
124
|
-
if ( method_exists( 'Newspack\Donations', 'is_donation_product' ) ) {
|
|
125
|
-
if ( \Newspack\Donations::is_donation_product( $product_id ) ) {
|
|
126
|
-
$action_type = 'donation';
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
return $action_type;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Returns an array of product information.
|
|
134
|
-
*
|
|
135
|
-
* @param int $product_id Product's ID.
|
|
136
|
-
* @param array $cart_item Cart item, if during checkout.
|
|
137
|
-
* @param WC_Order $order Completed order, if checkout is completed.
|
|
138
|
-
*
|
|
139
|
-
* @return array
|
|
140
|
-
*/
|
|
141
|
-
public static function build_js_data_events( $product_id, $cart_item = null, $order = null ) {
|
|
142
|
-
$data_order_details = [];
|
|
143
|
-
if ( empty( $product_id ) || ( empty( $cart_item ) && empty( $order ) ) ) {
|
|
144
|
-
return $data_order_details;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// Reassign the IDs to make sure the product is the product and the variation is the variation.
|
|
148
|
-
$product = \wc_get_product( $product_id );
|
|
149
|
-
$product_parent_id = $product->get_parent_id();
|
|
150
|
-
$variation_id = '';
|
|
151
|
-
if ( '' !== $product_parent_id && 0 !== $product_parent_id ) {
|
|
152
|
-
$variation_id = $product_id;
|
|
153
|
-
$product_id = $product_parent_id;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
$amount = 0;
|
|
157
|
-
$referrer = '';
|
|
158
|
-
if ( ! empty( $order ) ) {
|
|
159
|
-
$amount = $order->get_total();
|
|
160
|
-
$referrer = $order->get_meta( '_newspack_referer' );
|
|
161
|
-
} elseif ( ! empty( $cart_item ) ) {
|
|
162
|
-
$amount = $cart_item['data']->get_price();
|
|
163
|
-
$referrer = $cart_item['referer'];
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
$data_order_details = [
|
|
167
|
-
'amount' => $amount,
|
|
168
|
-
'action_type' => self::get_action_type( $product_id ),
|
|
169
|
-
'currency' => function_exists( 'get_woocommerce_currency' ) ? \get_woocommerce_currency() : 'USD',
|
|
170
|
-
'product_id' => strval( $product_id ),
|
|
171
|
-
'product_type' => self::get_product_type( $product_id ),
|
|
172
|
-
'referrer' => str_replace( home_url(), '', $referrer ), // Keeps format consistent for Homepage with Donate and Checkout Button blocks.
|
|
173
|
-
'recurrence' => self::get_purchase_recurrence( $product_id ),
|
|
174
|
-
'variation_id' => strval( $variation_id ),
|
|
175
|
-
];
|
|
176
|
-
$gate_post_id = ! empty( $order ) ? $order->get_meta( '_memberships_content_gate' ) : filter_input( INPUT_GET, 'memberships_content_gate', FILTER_SANITIZE_NUMBER_INT );
|
|
177
|
-
if ( $gate_post_id ) {
|
|
178
|
-
$data_order_details['gate_post_id'] = $gate_post_id;
|
|
179
|
-
}
|
|
180
|
-
$newspack_popup_id = ! empty( $order ) ? $order->get_meta( '_newspack_popup_id' ) : filter_input( INPUT_GET, 'newspack_popup_id', FILTER_SANITIZE_NUMBER_INT );
|
|
181
|
-
if ( $newspack_popup_id ) {
|
|
182
|
-
$data_order_details['newspack_popup_id'] = $newspack_popup_id;
|
|
183
|
-
}
|
|
184
|
-
return $data_order_details;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
52
|
/**
|
|
188
53
|
* Send data to GA4.
|
|
189
54
|
*
|
|
@@ -207,10 +72,10 @@ final class Data_Events {
|
|
|
207
72
|
$product_id = is_array( $data['platform_data']['product_id'] ) ? $data['platform_data']['product_id'][0] : $data['platform_data']['product_id'];
|
|
208
73
|
|
|
209
74
|
$data['action'] = self::FORM_SUBMISSION_SUCCESS;
|
|
210
|
-
$data['action_type'] =
|
|
75
|
+
$data['action_type'] = Checkout_Data::get_action_type( $product_id );
|
|
211
76
|
$data['product_id'] = $product_id;
|
|
212
|
-
$data['product_type'] =
|
|
213
|
-
$data['recurrence'] =
|
|
77
|
+
$data['product_type'] = Checkout_Data::get_product_type( $product_id );
|
|
78
|
+
$data['recurrence'] = Checkout_Data::get_purchase_recurrence( $product_id );
|
|
214
79
|
|
|
215
80
|
return $data;
|
|
216
81
|
}
|