PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 12.2.3
Jetpack – WP Security, Backup, Speed, & Growth v12.2.3
12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 13.9.2 14.0.1 14.1.1 14.2.2 14.3.1 14.4.2 14.5.1 14.6.1 14.7.1 14.8.1 14.9.2 15.0.3 15.1.2 15.2.1 15.3.2 15.4.1 15.5.1 15.6.1 15.7.2 15.8.1 15.9.2 16.0.2 16.1.3 16.2-a.5 16.2-a.3 16.1.2 16.2-a.1 16.1.1 16.1 16.1-beta 16.1-beta.2 16.1-beta.3 16.1-a.5 16.1-a.3 16.0.1 16.1-a.1 16.0 16.0-beta 16.0-a.7 16.0-a.5 15.9.1 16.0-a.3 16.0-a.1 15.9 15.9-beta 15.9-a.7 15.9-a.5 15.9-a.3 15.9-a.1 15.8 15.8-beta 15.8-a.7 15.8-a.5 5.2.5 5.3.4 5.4.4 5.5.5 5.6.5 5.7.5 5.8.4 5.9.4 6.0.4 6.1 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 6.2 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.3 6.3.1 6.3.2 6.3.3 6.3.4 6.3.5 6.3.6 6.3.7 6.4 6.4.1 6.4.2 6.4.3 6.4.4 6.4.5 6.4.6 6.5 6.5.1 6.5.2 6.5.3 6.5.4 6.6 6.6.1 6.6.2 6.6.3 6.6.4 6.6.5 6.7 6.7.1 6.7.2 6.7.3 6.7.4 6.8 6.8.1 6.8.2 6.8.3 6.8.4 6.8.5 6.9 6.9.1 6.9.2 6.9.3 6.9.4 7.0 7.0.1 7.0.2 7.0.3 7.0.4 7.0.5 7.1 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2 7.2.1 7.2.1.1 7.2.2 7.2.3 7.2.4 7.2.5 7.3 7.3.0.1 7.3.1 7.3.1.1 7.3.2 7.3.3 7.3.4 7.3.5 7.4 7.4.1 7.4.2 7.4.3 7.4.4 7.4.5 7.5 7.5.0.1 7.5.1 7.5.2 7.5.3 7.5.4 7.5.5 7.5.6 7.5.7 7.6 7.6.1 7.6.2 7.6.3 7.6.4 7.7 7.7.1 7.7.2 7.7.3 7.7.4 7.7.5 7.7.6 7.8 7.8.1 7.8.2 7.8.3 7.8.4 7.9 7.9.1 7.9.2 7.9.3 7.9.4 8.0 8.0.1 8.0.2 8.0.3 8.1 8.1.1 8.1.2 8.1.3 8.1.4 8.2 8.2.0.1 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.2.6 8.3 8.3.1 8.3.2 8.3.3 8.4 8.4.1 8.4.2 8.4.3 8.4.4 8.4.5 8.5 8.5.1 8.5.2 8.5.3 8.6 8.6.1 8.6.2 8.6.3 8.6.4 8.7 8.7.0.1 8.7.1 8.7.2 8.7.3 8.7.4 8.8 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.9 8.9.1 8.9.2 8.9.3 8.9.4 9.0 9.0.1 9.0.2 9.0.3 9.0.4 9.0.5 9.1 9.1.1 9.1.2 9.1.3 9.2 9.2.1 9.2.2 9.2.3 9.2.4 9.3 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.4 9.4.1 9.4.2 9.4.3 9.4.4 9.5 9.5.1 9.5.2 9.5.3 9.5.4 9.5.5 9.6 9.6.1 9.6.2 9.6.3 9.6.4 9.7 9.7.1 9.7.2 15.7-beta.2 9.7.3 15.7.1 9.8 15.8-a.1 9.8.1 15.8-a.3 9.8.2 2.0.9 9.8.3 2.1.7 9.9 2.2.10 9.9.1 2.3.10 9.9.2 2.4.7 9.9.3 2.5.5 2.6.6 2.7.5 2.8.5 2.9.6 3.0.6 3.1.5 3.2.5 3.3.6 3.4.6 3.5.6 3.6.4 3.7.5 3.8.5 3.9.10 4.0.7 4.1.4 4.2.5 4.3.5 4.4.5 4.5.3 4.6.3 4.7.4 4.8.5 4.9.3 5.0.3 5.1.4 trunk 10.0 10.0.1 10.0.2 10.1 10.1.1 10.1.2 10.2 10.2.1 10.2.2 10.2.3 10.3 10.3.1 10.3.2 10.4 10.4.1 10.4.2 10.5 10.5.1 10.5.2 10.5.3 10.6 10.6.1 10.6.2 10.7 10.7.1 10.7.2 10.8 10.8.1 10.8.2 10.9 10.9.1 10.9.2 10.9.3 11.0 11.0.1 11.0.2 11.1 11.1.1 11.1.2 11.1.3 11.1.4 11.2 11.2.1 11.2.2 11.3 11.3.1 11.3.2 11.3.3 11.3.4 11.4 11.4.1 11.4.2 11.5 11.5.1 11.5.2 11.5.3 11.6 11.6.1 11.6.2 11.7 11.7.1 11.7.2 11.7.3 11.8 11.8.3 11.8.4 11.8.5 11.8.6 11.9 11.9.1 11.9.2 11.9.3 12.0 12.0.1 12.0.2 12.1 12.1.1 12.1.2 12.2 12.2.1 12.2.2 12.3 12.3.1 12.4 12.4.1 12.5 12.5.1 12.6 12.6.1 12.6.2 12.6.3 12.7 12.7.1 12.7.2 12.8 12.8.1 12.8.2 12.9 12.9.1 12.9.2 12.9.3 12.9.4 13.0 13.0.1 13.1 13.1.1 13.1.2 13.1.3 13.1.4 13.2 13.2.1 13.2.2 13.2.3 13.3 13.3.1 13.3.2 13.4 13.4.1 13.4.2 13.4.3 13.4.4 13.5 13.5.1 13.6 13.6.1 13.7 13.7.1 13.8 13.8.1 13.8.2 13.9 13.9.1 14.0 14.1 14.2 14.2.1 14.3 14.4 14.4.1 14.5 14.6 14.7 14.8 14.9 14.9.1 15.0 15.0.1 15.0.2 15.1 15.1.1 15.2 15.3 15.3.1 15.4 15.5 15.6 15.7 15.7-a.1 15.7-a.3 15.7-a.5 15.7-a.7 15.7-beta
jetpack / modules / memberships / class-jetpack-memberships.php
jetpack / modules / memberships Last commit date
class-jetpack-memberships.php 3 years ago
class-jetpack-memberships.php
586 lines
1 <?php
2 /**
3 * Jetpack_Memberships: wrapper for memberships functions.
4 *
5 * @package Jetpack
6 * @since 7.3.0
7 */
8
9 use Automattic\Jetpack\Blocks;
10 use Automattic\Jetpack\Extensions\Premium_Content\Subscription_Service\Token_Subscription_Service;
11
12 require_once __DIR__ . '/../../extensions/blocks/subscriptions/constants.php';
13
14 /**
15 * Class Jetpack_Memberships
16 * This class represents the Memberships functionality.
17 */
18 class Jetpack_Memberships {
19 /**
20 * CSS class prefix to use in the styling.
21 *
22 * @var string
23 */
24 public static $css_classname_prefix = 'jetpack-memberships';
25 /**
26 * Our CPT type for the product (plan).
27 *
28 * @var string
29 */
30 public static $post_type_plan = 'jp_mem_plan';
31 /**
32 * Option that will store currently set up account (Stripe etc) id for memberships.
33 *
34 * @var string
35 */
36 public static $connected_account_id_option_name = 'jetpack-memberships-connected-account-id';
37
38 /**
39 * Post meta that will store the level of access for newsletters
40 *
41 * @var string
42 */
43 public static $newsletter_access_level_meta_name = \Automattic\Jetpack\Extensions\Subscriptions\META_NAME_FOR_POST_LEVEL_ACCESS_SETTINGS;
44
45 /**
46 * Button block type to use.
47 *
48 * @var string
49 */
50 private static $button_block_name = 'recurring-payments';
51
52 /**
53 * These are defaults for wp_kses ran on the membership button.
54 *
55 * @var array
56 */
57 private static $tags_allowed_in_the_button = array( 'br' => array() );
58
59 /**
60 * The minimum required plan for this Gutenberg block.
61 *
62 * @var string Plan slug
63 */
64 private static $required_plan;
65
66 /**
67 * Track recurring payments block registration.
68 *
69 * @var boolean True if block registration has been executed.
70 */
71 private static $has_registered_block = false;
72
73 /**
74 * Classic singleton pattern
75 *
76 * @var Jetpack_Memberships
77 */
78 private static $instance;
79
80 /**
81 * Cached results of user_can_view_post() method.
82 *
83 * @var array
84 */
85 private static $user_can_view_post_cache = array();
86
87 /**
88 * Currencies we support and Stripe's minimum amount for a transaction in that currency.
89 *
90 * @link https://stripe.com/docs/currencies#minimum-and-maximum-charge-amounts
91 *
92 * List has to be in with `SUPPORTED_CURRENCIES` in extensions/shared/currencies.js and
93 * `Memberships_Product::SUPPORTED_CURRENCIES` in the WP.com memberships library.
94 */
95 const SUPPORTED_CURRENCIES = array(
96 'USD' => 0.5,
97 'AUD' => 0.5,
98 'BRL' => 0.5,
99 'CAD' => 0.5,
100 'CHF' => 0.5,
101 'DKK' => 2.5,
102 'EUR' => 0.5,
103 'GBP' => 0.3,
104 'HKD' => 4.0,
105 'INR' => 0.5,
106 'JPY' => 50,
107 'MXN' => 10,
108 'NOK' => 3.0,
109 'NZD' => 0.5,
110 'PLN' => 2.0,
111 'SEK' => 3.0,
112 'SGD' => 0.5,
113 );
114
115 /**
116 * Jetpack_Memberships constructor.
117 */
118 private function __construct() {}
119
120 /**
121 * The actual constructor initializing the object.
122 *
123 * @return Jetpack_Memberships
124 */
125 public static function get_instance() {
126 if ( ! self::$instance ) {
127 self::$instance = new self();
128 self::$instance->register_init_hook();
129 // Yes, `pro-plan` with a dash, `jetpack_personal` with an underscore. Check the v1.5 endpoint to verify.
130 $wpcom_plan_slug = defined( 'ENABLE_PRO_PLAN' ) ? 'pro-plan' : 'personal-bundle';
131 self::$required_plan = ( defined( 'IS_WPCOM' ) && IS_WPCOM ) ? $wpcom_plan_slug : 'jetpack_personal';
132 }
133
134 return self::$instance;
135 }
136 /**
137 * Get the map that defines the shape of CPT post. keys are names of fields and
138 * 'meta' is the name of actual WP post meta field that corresponds.
139 *
140 * @return array
141 */
142 private static function get_plan_property_mapping() {
143 $meta_prefix = 'jetpack_memberships_';
144 $properties = array(
145 'price' => array(
146 'meta' => $meta_prefix . 'price',
147 ),
148 'currency' => array(
149 'meta' => $meta_prefix . 'currency',
150 ),
151 );
152 return $properties;
153 }
154
155 /**
156 * Inits further hooks on init hook.
157 */
158 private function register_init_hook() {
159 add_action( 'init', array( $this, 'init_hook_action' ) );
160 add_action( 'jetpack_register_gutenberg_extensions', array( $this, 'register_gutenberg_block' ) );
161 }
162
163 /**
164 * Actual hooks initializing on init.
165 */
166 public function init_hook_action() {
167 add_filter( 'rest_api_allowed_post_types', array( $this, 'allow_rest_api_types' ) );
168 add_filter( 'jetpack_sync_post_meta_whitelist', array( $this, 'allow_sync_post_meta' ) );
169 $this->setup_cpts();
170 }
171
172 /**
173 * Sets up the custom post types for the module.
174 */
175 private function setup_cpts() {
176 /*
177 * PLAN data structure.
178 */
179 $capabilities = array(
180 'edit_post' => 'edit_posts',
181 'read_post' => 'read_private_posts',
182 'delete_post' => 'delete_posts',
183 'edit_posts' => 'edit_posts',
184 'edit_others_posts' => 'edit_others_posts',
185 'publish_posts' => 'publish_posts',
186 'read_private_posts' => 'read_private_posts',
187 );
188 $order_args = array(
189 'label' => esc_html__( 'Plan', 'jetpack' ),
190 'description' => esc_html__( 'Recurring Payments plans', 'jetpack' ),
191 'supports' => array( 'title', 'custom-fields', 'content' ),
192 'hierarchical' => false,
193 'public' => false,
194 'show_ui' => false,
195 'show_in_menu' => false,
196 'show_in_admin_bar' => false,
197 'show_in_nav_menus' => false,
198 'can_export' => true,
199 'has_archive' => false,
200 'exclude_from_search' => true,
201 'publicly_queryable' => false,
202 'rewrite' => false,
203 'capabilities' => $capabilities,
204 'show_in_rest' => false,
205 );
206 register_post_type( self::$post_type_plan, $order_args );
207 }
208
209 /**
210 * Allows custom post types to be used by REST API.
211 *
212 * @param array $post_types - other post types.
213 *
214 * @see hook 'rest_api_allowed_post_types'
215 * @return array
216 */
217 public function allow_rest_api_types( $post_types ) {
218 $post_types[] = self::$post_type_plan;
219
220 return $post_types;
221 }
222
223 /**
224 * Allows custom meta fields to sync.
225 *
226 * @param array $post_meta - previously changet post meta.
227 *
228 * @return array
229 */
230 public function allow_sync_post_meta( $post_meta ) {
231 $meta_keys = array_map(
232 array( $this, 'return_meta' ),
233 self::get_plan_property_mapping()
234 );
235 return array_merge( $post_meta, array_values( $meta_keys ) );
236 }
237
238 /**
239 * This returns meta attribute of passet array.
240 * Used for array functions.
241 *
242 * @param array $map - stuff.
243 *
244 * @return mixed
245 */
246 public function return_meta( $map ) {
247 return $map['meta'];
248 }
249
250 /**
251 * Renders a preview of the Recurring Payment button, which is not hooked
252 * up to the subscription url. Used to preview the block on the frontend
253 * for site editors when Stripe has not been connected.
254 *
255 * @param array $attrs - attributes in the shortcode.
256 * @param string $content - Recurring Payment block content.
257 *
258 * @return string|void
259 */
260 public function render_button_preview( $attrs, $content = null ) {
261 if ( ! empty( $content ) ) {
262 $block_id = esc_attr( wp_unique_id( 'recurring-payments-block-' ) );
263 $content = str_replace( 'recurring-payments-id', $block_id, $content );
264 $content = str_replace( 'wp-block-jetpack-recurring-payments', 'wp-block-jetpack-recurring-payments wp-block-button', $content );
265 return $content;
266 }
267 return $this->deprecated_render_button_v1( $attrs, null );
268 }
269
270 /**
271 * Determines whether the button preview should be rendered. Returns true
272 * if the user has editing permissions, the button is not configured correctly
273 * (because it requires a plan upgrade or Stripe connection), and the
274 * button is a child of a Premium Content block.
275 *
276 * @param WP_Block $block Recurring Payments block instance.
277 *
278 * @return boolean
279 */
280 public function should_render_button_preview( $block ) {
281 $user_can_edit = static::user_can_edit();
282 $requires_stripe_connection = ! static::get_connected_account_id();
283
284 $jetpack_ready = ! self::is_enabled_jetpack_recurring_payments();
285
286 $is_premium_content_child = false;
287 if ( isset( $block ) && isset( $block->context['isPremiumContentChild'] ) ) {
288 $is_premium_content_child = (int) $block->context['isPremiumContentChild'];
289 }
290
291 return $is_premium_content_child &&
292 $user_can_edit &&
293 $requires_stripe_connection &&
294 $jetpack_ready;
295 }
296
297 /**
298 * Callback that parses the membership purchase shortcode.
299 *
300 * @param array $attributes - attributes in the shortcode. `id` here is the CPT id of the plan.
301 * @param string $content - Recurring Payment block content.
302 * @param WP_Block $block - Recurring Payment block instance.
303 *
304 * @return string|void
305 */
306 public function render_button( $attributes, $content = null, $block = null ) {
307 Jetpack_Gutenberg::load_assets_as_required( self::$button_block_name, array( 'thickbox', 'wp-polyfill' ) );
308
309 if ( $this->should_render_button_preview( $block ) ) {
310 return $this->render_button_preview( $attributes, $content );
311 }
312
313 if ( empty( $attributes['planId'] ) ) {
314 return;
315 }
316
317 $plan_id = (int) $attributes['planId'];
318 $product = get_post( $plan_id );
319 if ( ! $product || is_wp_error( $product ) ) {
320 return;
321 }
322 if ( $product->post_type !== self::$post_type_plan || 'publish' !== $product->post_status ) {
323 return;
324 }
325
326 add_thickbox();
327
328 if ( ! empty( $content ) ) {
329 $block_id = esc_attr( wp_unique_id( 'recurring-payments-block-' ) );
330 $content = str_replace( 'recurring-payments-id', $block_id, $content );
331 $content = str_replace( 'wp-block-jetpack-recurring-payments', 'wp-block-jetpack-recurring-payments wp-block-button', $content );
332 $subscribe_url = $this->get_subscription_url( $plan_id );
333 return preg_replace( '/(href=".*")/U', 'href="' . $subscribe_url . '"', $content );
334 }
335
336 return $this->deprecated_render_button_v1( $attributes, $plan_id );
337 }
338
339 /**
340 * Builds subscription URL for this membership using the current blog and
341 * supplied plan IDs.
342 *
343 * @param integer $plan_id - Unique ID for the plan being subscribed to.
344 * @return string
345 */
346 public function get_subscription_url( $plan_id ) {
347 global $wp;
348
349 return add_query_arg(
350 array(
351 'blog' => esc_attr( self::get_blog_id() ),
352 'plan' => esc_attr( $plan_id ),
353 'lang' => esc_attr( get_locale() ),
354 'pid' => esc_attr( get_the_ID() ), // Needed for analytics purposes.
355 'redirect' => esc_attr( rawurlencode( home_url( $wp->request ) ) ), // Needed for redirect back in case of redirect-based flow.
356 ),
357 'https://subscribe.wordpress.com/memberships/'
358 );
359 }
360
361 /**
362 * Renders a deprecated legacy version of the button HTML.
363 *
364 * @param array $attrs - Array containing the Recurring Payment block attributes.
365 * @param integer $plan_id - Unique plan ID the membership is for.
366 *
367 * @return string
368 */
369 public function deprecated_render_button_v1( $attrs, $plan_id ) {
370 $button_label = isset( $attrs['submitButtonText'] )
371 ? $attrs['submitButtonText']
372 : __( 'Your contribution', 'jetpack' );
373
374 $button_styles = array();
375 if ( ! empty( $attrs['customBackgroundButtonColor'] ) ) {
376 array_push(
377 $button_styles,
378 sprintf(
379 'background-color: %s',
380 sanitize_hex_color( $attrs['customBackgroundButtonColor'] )
381 )
382 );
383 }
384 if ( ! empty( $attrs['customTextButtonColor'] ) ) {
385 array_push(
386 $button_styles,
387 sprintf(
388 'color: %s',
389 sanitize_hex_color( $attrs['customTextButtonColor'] )
390 )
391 );
392 }
393 $button_styles = implode( ';', $button_styles );
394
395 return sprintf(
396 '<div class="%1$s"><a role="button" %6$s href="%2$s" class="%3$s" style="%4$s">%5$s</a></div>',
397 esc_attr(
398 Blocks::classes(
399 self::$button_block_name,
400 $attrs,
401 array( 'wp-block-button' )
402 )
403 ),
404 esc_url( $this->get_subscription_url( $plan_id ) ),
405 isset( $attrs['submitButtonClasses'] ) ? esc_attr( $attrs['submitButtonClasses'] ) : 'wp-block-button__link',
406 esc_attr( $button_styles ),
407 wp_kses( $button_label, self::$tags_allowed_in_the_button ),
408 isset( $attrs['submitButtonAttributes'] ) ? sanitize_text_field( $attrs['submitButtonAttributes'] ) : '' // Needed for arbitrary target=_blank on WPCOM VIP.
409 );
410 }
411
412 /**
413 * Get current blog id.
414 *
415 * @return int
416 */
417 public static function get_blog_id() {
418 if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
419 return get_current_blog_id();
420 }
421
422 return Jetpack_Options::get_option( 'id' );
423 }
424
425 /**
426 * Get the id of the connected payment acount (Stripe etc).
427 *
428 * @return int|void
429 */
430 public static function get_connected_account_id() {
431 return get_option( self::$connected_account_id_option_name );
432 }
433
434 /**
435 * Get the newsletter access level
436 *
437 * @return string|void
438 */
439 public static function get_newsletter_access_level() {
440 return get_post_meta( get_the_ID(), self::$newsletter_access_level_meta_name, true );
441 }
442
443 /**
444 * Determines whether the current user can edit.
445 *
446 * @return bool Whether the user can edit.
447 */
448 public static function user_can_edit() {
449 $user = wp_get_current_user();
450 // phpcs:ignore ImportDetection.Imports.RequireImports.Symbol
451 return 0 !== $user->ID && current_user_can( 'edit_post', get_the_ID() );
452 }
453
454 /**
455 * Determines whether the current user can view the post based on the newsletter access level
456 * and caches the result.
457 *
458 * @return bool Whether the post can be viewed
459 */
460 public static function user_can_view_post() {
461 $user_id = get_current_user_id();
462 $post_id = get_the_ID() || 0;
463 $cache_key = sprintf( '%d_%d', $user_id, $post_id );
464
465 if ( isset( self::$user_can_view_post_cache[ $cache_key ] ) ) {
466 return self::$user_can_view_post_cache[ $cache_key ];
467 }
468
469 $value = self::user_can_view_post_nocache();
470 self::$user_can_view_post_cache[ $cache_key ] = $value;
471 return $value;
472 }
473
474 /**
475 * Determines whether the post can be viewed based on the newsletter access level
476 *
477 * @return bool Whether the post can be viewed
478 */
479 public static function user_can_view_post_nocache() {
480 require_once JETPACK__PLUGIN_DIR . 'extensions/blocks/premium-content/_inc/subscription-service/include.php';
481
482 $newsletter_access_level = self::get_newsletter_access_level();
483
484 if ( ! $newsletter_access_level || Token_Subscription_Service::POST_ACCESS_LEVEL_EVERYBODY === $newsletter_access_level ) {
485 // The post is not gated, we return early
486 return true;
487 }
488
489 $paywall = \Automattic\Jetpack\Extensions\Premium_Content\subscription_service();
490 return $paywall->visitor_can_view_content( self::get_all_plans_id_jetpack_recurring_payments(), $newsletter_access_level );
491 }
492
493 /**
494 * Whether Recurring Payments are enabled. True if the block
495 * is supported by the site's plan, or if it is a Jetpack site
496 * and the feature to enable upgrade nudges is active.
497 *
498 * @return bool
499 */
500 public static function is_enabled_jetpack_recurring_payments() {
501 $api_available = ( ( defined( 'IS_WPCOM' ) && IS_WPCOM ) || Jetpack::is_connection_ready() );
502 return $api_available;
503 }
504
505 /**
506 * Whether site has any paid plan.
507 *
508 * @param string $type - Type of a plan for which site is configured. For now supports empty and newsletter.
509 *
510 * @return bool
511 */
512 public static function has_configured_plans_jetpack_recurring_payments( $type = '' ) {
513 if ( ! self::is_enabled_jetpack_recurring_payments() ) {
514 return false;
515 }
516 $query = array(
517 'post_type' => self::$post_type_plan,
518 'posts_per_page' => 1,
519 );
520
521 // We want to see if user has any plan marked as a newsletter set up.
522 if ( 'newsletter' === $type ) {
523 $query['meta_key'] = 'jetpack_memberships_site_subscriber';
524 $query['meta_value'] = true;
525 }
526
527 $plans = get_posts( $query );
528 return ( is_countable( $plans ) && count( $plans ) > 0 );
529 }
530
531 /**
532 * Return all plans
533 *
534 * @return array
535 */
536 public static function get_all_plans_id_jetpack_recurring_payments() {
537 if ( ! self::is_enabled_jetpack_recurring_payments() ) {
538 return array();
539 }
540 return get_posts(
541 array(
542 'post_type' => self::$post_type_plan,
543 'posts_per_page' => -1,
544 'fields' => 'ids',
545 )
546 );
547 }
548
549 /**
550 * Register the Recurring Payments Gutenberg block
551 */
552 public function register_gutenberg_block() {
553 // This gate was introduced to prevent duplicate registration. A race condition exists where
554 // the registration that happens via extensions/blocks/recurring-payments/recurring-payments.php
555 // was adding the registration action after the action had been run in some contexts.
556 if ( self::$has_registered_block ) {
557 return;
558 }
559
560 if ( self::is_enabled_jetpack_recurring_payments() ) {
561 Blocks::jetpack_register_block(
562 'jetpack/recurring-payments',
563 array(
564 'render_callback' => array( $this, 'render_button' ),
565 'uses_context' => array( 'isPremiumContentChild' ),
566 'provides_context' => array(
567 'jetpack/parentBlockWidth' => 'width',
568 ),
569 )
570 );
571 } else {
572 Jetpack_Gutenberg::set_extension_unavailable(
573 'jetpack/recurring-payments',
574 'missing_plan',
575 array(
576 'required_feature' => 'memberships',
577 'required_plan' => self::$required_plan,
578 )
579 );
580 }
581
582 self::$has_registered_block = true;
583 }
584 }
585 Jetpack_Memberships::get_instance();
586