summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/jetpack/modules/memberships/class-jetpack-memberships.php')
-rw-r--r--plugins/jetpack/modules/memberships/class-jetpack-memberships.php219
1 files changed, 182 insertions, 37 deletions
diff --git a/plugins/jetpack/modules/memberships/class-jetpack-memberships.php b/plugins/jetpack/modules/memberships/class-jetpack-memberships.php
index 5a3ed64f..ae8a3d8a 100644
--- a/plugins/jetpack/modules/memberships/class-jetpack-memberships.php
+++ b/plugins/jetpack/modules/memberships/class-jetpack-memberships.php
@@ -6,6 +6,8 @@
* @since 7.3.0
*/
+use Automattic\Jetpack\Blocks;
+
/**
* Class Jetpack_Memberships
* This class represents the Memberships functionality.
@@ -65,6 +67,34 @@ class Jetpack_Memberships {
private static $instance;
/**
+ * Currencies we support and Stripe's minimum amount for a transaction in that currency.
+ *
+ * @link https://stripe.com/docs/currencies#minimum-and-maximum-charge-amounts
+ *
+ * List has to be in with `SUPPORTED_CURRENCIES` in extensions/shared/currencies.js and
+ * `Memberships_Product::SUPPORTED_CURRENCIES` in the WP.com memberships library.
+ */
+ const SUPPORTED_CURRENCIES = array(
+ 'USD' => 0.5,
+ 'AUD' => 0.5,
+ 'BRL' => 0.5,
+ 'CAD' => 0.5,
+ 'CHF' => 0.5,
+ 'DKK' => 2.5,
+ 'EUR' => 0.5,
+ 'GBP' => 0.3,
+ 'HKD' => 4.0,
+ 'INR' => 0.5,
+ 'JPY' => 50,
+ 'MXN' => 10,
+ 'NOK' => 3.0,
+ 'NZD' => 0.5,
+ 'PLN' => 2.0,
+ 'SEK' => 3.0,
+ 'SGD' => 0.5,
+ );
+
+ /**
* Jetpack_Memberships constructor.
*/
private function __construct() {}
@@ -197,21 +227,77 @@ class Jetpack_Memberships {
public function return_meta( $map ) {
return $map['meta'];
}
+
+ /**
+ * Renders a preview of the Recurring Payment button, which is not hooked
+ * up to the subscription url. Used to preview the block on the frontend
+ * for site editors when Stripe has not been connected.
+ *
+ * @param array $attrs - attributes in the shortcode.
+ * @param string $content - Recurring Payment block content.
+ *
+ * @return string|void
+ */
+ public function render_button_preview( $attrs, $content = null ) {
+ if ( ! empty( $content ) ) {
+ $block_id = esc_attr( wp_unique_id( 'recurring-payments-block-' ) );
+ $content = str_replace( 'recurring-payments-id', $block_id, $content );
+ $content = str_replace( 'wp-block-jetpack-recurring-payments', 'wp-block-jetpack-recurring-payments wp-block-button', $content );
+ return $content;
+ }
+ return $this->deprecated_render_button_v1( $attrs, null );
+ }
+
+ /**
+ * Determines whether the button preview should be rendered. Returns true
+ * if the user has editing permissions, the button is not configured correctly
+ * (because it requires a plan upgrade or Stripe connection), and the
+ * button is a child of a Premium Content block.
+ *
+ * @param WP_Block $block Recurring Payments block instance.
+ *
+ * @return boolean
+ */
+ public function should_render_button_preview( $block ) {
+ $user_can_edit = $this->user_can_edit();
+ $requires_stripe_connection = ! $this->get_connected_account_id();
+
+ $requires_upgrade = ! self::is_supported_jetpack_recurring_payments();
+
+ $is_premium_content_child = false;
+ if ( isset( $block ) && isset( $block->context['isPremiumContentChild'] ) ) {
+ $is_premium_content_child = (int) $block->context['isPremiumContentChild'];
+ }
+
+ return (
+ $is_premium_content_child &&
+ $user_can_edit &&
+ ( $requires_upgrade || $requires_stripe_connection )
+ );
+ }
+
/**
* Callback that parses the membership purchase shortcode.
*
- * @param array $attrs - attributes in the shortcode. `id` here is the CPT id of the plan.
+ * @param array $attributes - attributes in the shortcode. `id` here is the CPT id of the plan.
+ * @param string $content - Recurring Payment block content.
+ * @param WP_Block $block - Recurring Payment block instance.
*
* @return string|void
*/
- public function render_button( $attrs ) {
+ public function render_button( $attributes, $content = null, $block = null ) {
Jetpack_Gutenberg::load_assets_as_required( self::$button_block_name, array( 'thickbox', 'wp-polyfill' ) );
- if ( empty( $attrs['planId'] ) ) {
+ if ( $this->should_render_button_preview( $block ) ) {
+ return $this->render_button_preview( $attributes, $content );
+ }
+
+ if ( empty( $attributes['planId'] ) ) {
return;
}
- $id = intval( $attrs['planId'] );
- $product = get_post( $id );
+
+ $plan_id = (int) $attributes['planId'];
+ $product = get_post( $plan_id );
if ( ! $product || is_wp_error( $product ) ) {
return;
}
@@ -219,28 +305,54 @@ class Jetpack_Memberships {
return;
}
- $data = array(
- 'blog_id' => self::get_blog_id(),
- 'id' => $id,
- 'button_label' => __( 'Your contribution', 'jetpack' ),
- 'powered_text' => __( 'Powered by WordPress.com', 'jetpack' ),
- );
+ add_thickbox();
+
+ if ( ! empty( $content ) ) {
+ $block_id = esc_attr( wp_unique_id( 'recurring-payments-block-' ) );
+ $content = str_replace( 'recurring-payments-id', $block_id, $content );
+ $content = str_replace( 'wp-block-jetpack-recurring-payments', 'wp-block-jetpack-recurring-payments wp-block-button', $content );
+ $subscribe_url = $this->get_subscription_url( $plan_id );
+ return str_replace( 'href="#"', 'href="' . $subscribe_url . '"', $content );
+ }
+
+ return $this->deprecated_render_button_v1( $attributes, $plan_id );
+ }
+
+ /**
+ * Builds subscription URL for this membership using the current blog and
+ * supplied plan IDs.
+ *
+ * @param integer $plan_id - Unique ID for the plan being subscribed to.
+ * @return string
+ */
+ public function get_subscription_url( $plan_id ) {
+ global $wp;
- $classes = Jetpack_Gutenberg::block_classes(
- self::$button_block_name,
- $attrs,
+ return add_query_arg(
array(
- 'wp-block-button__link',
- 'components-button',
- 'is-primary',
- 'is-button',
- self::$css_classname_prefix . '-' . $data['id'],
- )
+ 'blog' => esc_attr( self::get_blog_id() ),
+ 'plan' => esc_attr( $plan_id ),
+ 'lang' => esc_attr( get_locale() ),
+ 'pid' => esc_attr( get_the_ID() ), // Needed for analytics purposes.
+ 'redirect' => esc_attr( rawurlencode( home_url( $wp->request ) ) ), // Needed for redirect back in case of redirect-based flow.
+ ),
+ 'https://subscribe.wordpress.com/memberships/'
);
+ }
+
+ /**
+ * Renders a deprecated legacy version of the button HTML.
+ *
+ * @param array $attrs - Array containing the Recurring Payment block attributes.
+ * @param integer $plan_id - Unique plan ID the membership is for.
+ *
+ * @return string
+ */
+ public function deprecated_render_button_v1( $attrs, $plan_id ) {
+ $button_label = isset( $attrs['submitButtonText'] )
+ ? $attrs['submitButtonText']
+ : __( 'Your contribution', 'jetpack' );
- if ( isset( $attrs['submitButtonText'] ) ) {
- $data['button_label'] = $attrs['submitButtonText'];
- }
$button_styles = array();
if ( ! empty( $attrs['customBackgroundButtonColor'] ) ) {
array_push(
@@ -261,16 +373,21 @@ class Jetpack_Memberships {
);
}
$button_styles = implode( ';', $button_styles );
- add_thickbox();
+
return sprintf(
- '<button data-blog-id="%d" data-powered-text="%s" data-plan-id="%d" data-lang="%s" class="%s" style="%s">%s</button>',
- esc_attr( $data['blog_id'] ),
- esc_attr( $data['powered_text'] ),
- esc_attr( $data['id'] ),
- esc_attr( get_locale() ),
- esc_attr( $classes ),
+ '<div class="%1$s"><a role="button" %6$s href="%2$s" class="%3$s" style="%4$s">%5$s</a></div>',
+ esc_attr(
+ Jetpack_Gutenberg::block_classes(
+ self::$button_block_name,
+ $attrs,
+ array( 'wp-block-button' )
+ )
+ ),
+ esc_url( $this->get_subscription_url( $plan_id ) ),
+ isset( $attrs['submitButtonClasses'] ) ? esc_attr( $attrs['submitButtonClasses'] ) : 'wp-block-button__link',
esc_attr( $button_styles ),
- wp_kses( $data['button_label'], self::$tags_allowed_in_the_button )
+ wp_kses( $button_label, self::$tags_allowed_in_the_button ),
+ isset( $attrs['submitButtonAttributes'] ) ? sanitize_text_field( $attrs['submitButtonAttributes'] ) : '' // Needed for arbitrary target=_blank on WPCOM VIP.
);
}
@@ -297,21 +414,46 @@ class Jetpack_Memberships {
}
/**
- * Whether Recurring Payments are enabled.
+ * Determines whether the current user can edit.
+ *
+ * @return bool Whether the user can edit.
+ */
+ public static function user_can_edit() {
+ $user = wp_get_current_user();
+ // phpcs:ignore ImportDetection.Imports.RequireImports.Symbol
+ return 0 !== $user->ID && current_user_can( 'edit_post', get_the_ID() );
+ }
+
+ /**
+ * Whether Recurring Payments are enabled. True if the block
+ * is supported by the site's plan, or if it is a Jetpack site
+ * and the feature to enable upgrade nudges is active.
*
* @return bool
*/
public static function is_enabled_jetpack_recurring_payments() {
+ return (
+ self::is_supported_jetpack_recurring_payments() ||
+ (
+ Jetpack::is_connection_ready() &&
+ /** This filter is documented in class.jetpack-gutenberg.php */
+ ! apply_filters( 'jetpack_block_editor_enable_upgrade_nudge', false )
+ )
+ );
+ }
+
+ /**
+ * Whether the site's plan supports the Recurring Payments block.
+ */
+ public static function is_supported_jetpack_recurring_payments() {
// For WPCOM sites.
if ( defined( 'IS_WPCOM' ) && IS_WPCOM && function_exists( 'has_any_blog_stickers' ) ) {
$site_id = get_current_blog_id();
return has_any_blog_stickers( array( 'personal-plan', 'premium-plan', 'business-plan', 'ecommerce-plan' ), $site_id );
}
-
// For Jetpack sites.
- return Jetpack::is_active() && (
- /** This filter is documented in class.jetpack-gutenberg.php */
- ! apply_filters( 'jetpack_block_editor_enable_upgrade_nudge', false ) || // Remove when the default becomes `true`.
+ return (
+ Jetpack::is_connection_ready() &&
Jetpack_Plan::supports( 'recurring-payments' )
);
}
@@ -328,10 +470,13 @@ class Jetpack_Memberships {
}
if ( self::is_enabled_jetpack_recurring_payments() ) {
- jetpack_register_block(
+ $deprecated = function_exists( 'gutenberg_get_post_from_context' );
+ $uses = $deprecated ? 'context' : 'uses_context';
+ Blocks::jetpack_register_block(
'jetpack/recurring-payments',
array(
'render_callback' => array( $this, 'render_button' ),
+ $uses => array( 'isPremiumContentChild' ),
)
);
} else {