PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 13.1.5
Jetpack – WP Security, Backup, Speed, & Growth v13.1.5
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 / extensions / blocks / subscriptions / subscriptions.php
jetpack / extensions / blocks / subscriptions Last commit date
constants.php 2 years ago subscriptions.php 2 years ago
subscriptions.php
1224 lines
1 <?php
2 /**
3 * Subscriptions Block.
4 *
5 * @package automattic/jetpack
6 */
7
8 namespace Automattic\Jetpack\Extensions\Subscriptions;
9
10 use Automattic\Jetpack\Blocks;
11 use Automattic\Jetpack\Connection\Manager as Connection_Manager;
12 use Automattic\Jetpack\Extensions\Premium_Content\Subscription_Service\Abstract_Token_Subscription_Service;
13 use Automattic\Jetpack\Extensions\Premium_Content\Subscription_Service\Jetpack_Token_Subscription_Service;
14 use Automattic\Jetpack\Status;
15 use Automattic\Jetpack\Status\Host;
16 use Jetpack;
17 use Jetpack_Gutenberg;
18 use Jetpack_Memberships;
19 use Jetpack_Subscriptions_Widget;
20
21 require_once __DIR__ . '/constants.php';
22 require_once JETPACK__PLUGIN_DIR . 'extensions/blocks/premium-content/_inc/subscription-service/include.php';
23
24 /**
25 * These block defaults should match ./constants.js
26 */
27 const DEFAULT_BORDER_RADIUS_VALUE = 0;
28 const DEFAULT_BORDER_WEIGHT_VALUE = 1;
29 const DEFAULT_FONTSIZE_VALUE = '16px';
30 const DEFAULT_PADDING_VALUE = 15;
31 const DEFAULT_SPACING_VALUE = 10;
32
33 /**
34 * Registers the block for use in Gutenberg
35 * This is done via an action so that we can disable
36 * registration if we need to.
37 */
38 function register_block() {
39 /*
40 * Disable the feature on P2 blogs
41 */
42 if ( function_exists( '\WPForTeams\is_wpforteams_site' ) &&
43 \WPForTeams\is_wpforteams_site( get_current_blog_id() ) ) {
44 return;
45 }
46
47 if (
48 ( defined( 'IS_WPCOM' ) && IS_WPCOM )
49 || ( ( new Connection_Manager( 'jetpack' ) )->has_connected_owner() && ! ( new Status() )->is_offline_mode() )
50 ) {
51 Blocks::jetpack_register_block(
52 __DIR__,
53 array(
54 'render_callback' => __NAMESPACE__ . '\render_block',
55 'supports' => array(
56 'spacing' => array(
57 'margin' => true,
58 'padding' => true,
59 ),
60 'align' => array( 'wide', 'full' ),
61 ),
62 )
63 );
64 }
65
66 /*
67 * If the Subscriptions module is not active,
68 * do not make any further changes on the site.
69 */
70 if ( ! Jetpack::is_module_active( 'subscriptions' ) ) {
71 return;
72 }
73
74 /**
75 * Do not proceed if the newsletter feature is not enabled
76 * or if the 'Jetpack_Memberships' class does not exists.
77 */
78 if ( ! class_exists( '\Jetpack_Memberships' ) ) {
79 return;
80 }
81
82 register_post_meta(
83 'post',
84 META_NAME_FOR_POST_LEVEL_ACCESS_SETTINGS,
85 array(
86 'show_in_rest' => true,
87 'single' => true,
88 'type' => 'string',
89 'auth_callback' => function () {
90 return wp_get_current_user()->has_cap( 'edit_posts' );
91 },
92 )
93 );
94
95 register_post_meta(
96 'post',
97 META_NAME_FOR_POST_DONT_EMAIL_TO_SUBS,
98 array(
99 'default' => false,
100 'show_in_rest' => true,
101 'single' => true,
102 'type' => 'boolean',
103 'auth_callback' => function () {
104 return wp_get_current_user()->has_cap( 'edit_posts' );
105 },
106 )
107 );
108
109 register_post_meta(
110 'post',
111 META_NAME_FOR_POST_TIER_ID_SETTINGS,
112 array(
113 'show_in_rest' => true,
114 'single' => true,
115 'type' => 'integer',
116 'auth_callback' => function () {
117 return wp_get_current_user()->has_cap( 'edit_posts' );
118 },
119 )
120 );
121
122 // This ensures Jetpack will sync this post meta to WPCOM.
123 add_filter(
124 'jetpack_sync_post_meta_whitelist',
125 function ( $allowed_meta ) {
126 return array_merge(
127 $allowed_meta,
128 array(
129 META_NAME_FOR_POST_LEVEL_ACCESS_SETTINGS,
130 META_NAME_FOR_POST_DONT_EMAIL_TO_SUBS,
131 )
132 );
133 }
134 );
135
136 // Hide the content – Priority 8 makes it run before do_blocks gets called for the content
137 add_filter( 'the_content', __NAMESPACE__ . '\add_paywall', 8 );
138
139 // Close comments on the front-end
140 add_filter( 'comments_open', __NAMESPACE__ . '\maybe_close_comments', 10, 2 );
141 add_filter( 'pings_open', __NAMESPACE__ . '\maybe_close_comments', 10, 2 );
142
143 // Hide existing comments
144 add_filter( 'get_comment', __NAMESPACE__ . '\maybe_gate_existing_comments' );
145
146 // Gate the excerpt for a post
147 add_filter( 'get_the_excerpt', __NAMESPACE__ . '\jetpack_filter_excerpt_for_newsletter', 10, 2 );
148
149 // Add a 'Newsletter' column to the Edit posts page
150 // We only display the "Newsletter" column if we have configured the paid newsletter plan
151 if ( Jetpack_Memberships::has_configured_plans_jetpack_recurring_payments( 'newsletter' ) ) {
152 add_action( 'manage_post_posts_columns', __NAMESPACE__ . '\register_newsletter_access_column' );
153 add_action( 'manage_post_posts_custom_column', __NAMESPACE__ . '\render_newsletter_access_rows', 10, 2 );
154 add_action( 'admin_head', __NAMESPACE__ . '\newsletter_access_column_styles' );
155 }
156 }
157 add_action( 'init', __NAMESPACE__ . '\register_block', 9 );
158
159 /**
160 * Returns true when in a WP.com environment.
161 *
162 * @return boolean
163 */
164 function is_wpcom() {
165 return defined( 'IS_WPCOM' ) && IS_WPCOM;
166 }
167
168 /**
169 * Adds a 'Newsletter' column after the 'Title' column in the post list
170 *
171 * @param array $columns An array of column names.
172 * @return array An array of column names.
173 */
174 function register_newsletter_access_column( $columns ) {
175 $position = array_search( 'title', array_keys( $columns ), true );
176 $new_column = array( NEWSLETTER_COLUMN_ID => __( 'Newsletter', 'jetpack' ) );
177 return array_merge(
178 array_slice( $columns, 0, $position + 1, true ),
179 $new_column,
180 array_slice( $columns, $position, null, true )
181 );
182 }
183
184 /**
185 * Displays the newsletter access level.
186 *
187 * @param string $column_id The ID of the column to display.
188 * @param int $post_id The current post ID.
189 */
190 function render_newsletter_access_rows( $column_id, $post_id ) {
191 if ( NEWSLETTER_COLUMN_ID !== $column_id ) {
192 return;
193 }
194
195 $access_level = get_post_meta( $post_id, META_NAME_FOR_POST_LEVEL_ACCESS_SETTINGS, true );
196
197 switch ( $access_level ) {
198 case Abstract_Token_Subscription_Service::POST_ACCESS_LEVEL_PAID_SUBSCRIBERS_ALL_TIERS:
199 echo esc_html__( 'Paid Subscribers (all plans)', 'jetpack' );
200 break;
201 case Abstract_Token_Subscription_Service::POST_ACCESS_LEVEL_PAID_SUBSCRIBERS:
202 echo esc_html__( 'Paid Subscribers', 'jetpack' );
203 break;
204 case Abstract_Token_Subscription_Service::POST_ACCESS_LEVEL_SUBSCRIBERS:
205 echo esc_html__( 'Subscribers', 'jetpack' );
206 break;
207 case Abstract_Token_Subscription_Service::POST_ACCESS_LEVEL_EVERYBODY:
208 echo esc_html__( 'Everybody', 'jetpack' );
209 break;
210 default:
211 echo '';
212 }
213 }
214
215 /**
216 * Adds the Newsletter column styles
217 */
218 function newsletter_access_column_styles() {
219 echo '<style id="jetpack-newsletter-newsletter-access-column"> table.fixed .column-newsletter_access { width: 10%; } </style>';
220 }
221
222 /**
223 * Determine the amount of folks currently subscribed to the blog, splitted out in email_subscribers & social_followers & paid_subscribers
224 *
225 * @return array containing ['value' => ['email_subscribers' => 0, 'paid_subscribers' => 0, 'social_followers' => 0]]
226 */
227 function fetch_subscriber_counts() {
228 $subs_count = 0;
229 if ( is_wpcom() ) {
230 $subs_count = array(
231 'value' => \wpcom_fetch_subs_counts( true ),
232 );
233 } else {
234 $cache_key = 'wpcom_subscribers_totals';
235 $subs_count = get_transient( $cache_key );
236 if ( false === $subs_count || 'failed' === $subs_count['status'] ) {
237 $xml = new \Jetpack_IXR_Client();
238 $xml->query( 'jetpack.fetchSubscriberCounts' );
239
240 if ( $xml->isError() ) { // If we get an error from .com, set the status to failed so that we will try again next time the data is requested.
241 $subs_count = array(
242 'status' => 'failed',
243 'code' => $xml->getErrorCode(),
244 'message' => $xml->getErrorMessage(),
245 'value' => ( isset( $subs_count['value'] ) ) ? $subs_count['value'] : array(
246 'email_subscribers' => 0,
247 'social_followers' => 0,
248 'paid_subscribers' => 0,
249 ),
250 );
251 } else {
252 $subs_count = array(
253 'status' => 'success',
254 'value' => $xml->getResponse(),
255 );
256 }
257 set_transient( $cache_key, $subs_count, 3600 ); // Try to cache the result for at least 1 hour.
258 }
259 }
260 return $subs_count;
261 }
262
263 /**
264 * Returns subscriber count based on include_social_followers attribute
265 *
266 * @param bool $include_social_followers Whether to include social followers in the count.
267 * @return int
268 */
269 function get_subscriber_count( $include_social_followers ) {
270 $counts = fetch_subscriber_counts();
271
272 if ( $include_social_followers ) {
273 $subscriber_count = $counts['value']['email_subscribers'] + $counts['value']['social_followers'];
274 } else {
275 $subscriber_count = $counts['value']['email_subscribers'];
276 }
277 return $subscriber_count;
278 }
279
280 /**
281 * Returns true if the block attributes contain a value for the given key.
282 *
283 * @param array $attributes Array containing the block attributes.
284 * @param string $key Block attribute key.
285 *
286 * @return boolean
287 */
288 function has_attribute( $attributes, $key ) {
289 return isset( $attributes[ $key ] ) && $attributes[ $key ] !== 'undefined';
290 }
291
292 /**
293 * Returns the value for the given attribute key, with the option of providing a default fallback value.
294 *
295 * @param array $attributes Array containing the block attributes.
296 * @param string $key Block attribute key.
297 * @param mixed $default Optional fallback value in case the key doesn't exist.
298 *
299 * @return mixed
300 */
301 function get_attribute( $attributes, $key, $default = null ) {
302 return has_attribute( $attributes, $key ) ? $attributes[ $key ] : $default;
303 }
304
305 /**
306 * Mimics getColorClassName, getFontSizeClass and getGradientClass from @wordpress/block-editor js package.
307 *
308 * @param string $setting Setting name.
309 * @param string $value Setting value.
310 *
311 * @return string
312 */
313 function get_setting_class_name( $setting, $value ) {
314 if ( ! $setting || ! $value ) {
315 return '';
316 }
317
318 return sprintf( 'has-%s-%s', $value, $setting );
319 }
320
321 /**
322 * Uses block attributes to generate an array containing the classes for various block elements.
323 * Based on Jetpack_Subscriptions_Widget::do_subscription_form() which the block was originally using.
324 *
325 * @param array $attributes Array containing the block attributes.
326 *
327 * @return array
328 */
329 function get_element_class_names_from_attributes( $attributes ) {
330 $text_color_class = get_setting_class_name( 'color', get_attribute( $attributes, 'textColor' ) );
331 $font_size_class = get_setting_class_name( 'font-size', get_attribute( $attributes, 'fontSize' ) );
332 $border_class = get_setting_class_name( 'border-color', get_attribute( $attributes, 'borderColor' ) );
333
334 $button_background_class = get_setting_class_name( 'background-color', get_attribute( $attributes, 'buttonBackgroundColor' ) );
335 $button_gradient_class = get_setting_class_name( 'gradient-background', get_attribute( $attributes, 'buttonGradient' ) );
336
337 $email_field_background_class = get_setting_class_name( 'background-color', get_attribute( $attributes, 'emailFieldBackgroundColor' ) );
338 $email_field_gradient_class = get_setting_class_name( 'gradient-background', get_attribute( $attributes, 'emailFieldGradient' ) );
339
340 $submit_button_classes = array_filter(
341 array(
342 'wp-block-button__link' => true,
343 'no-border-radius' => 0 === get_attribute( $attributes, 'borderRadius', 0 ),
344 $font_size_class => true,
345 $border_class => true,
346 'has-text-color' => ! empty( $text_color_class ),
347 $text_color_class => true,
348 'has-background' => ! empty( $button_background_class ) || ! empty( $button_gradient_class ),
349 $button_background_class => ! empty( $button_background_class ),
350 $button_gradient_class => ! empty( $button_gradient_class ),
351 )
352 );
353
354 $email_field_classes = array_filter(
355 array(
356 'no-border-radius' => 0 === get_attribute( $attributes, 'borderRadius', 0 ),
357 $font_size_class => true,
358 $border_class => true,
359 $email_field_background_class => true,
360 $email_field_gradient_class => true,
361 )
362 );
363
364 $block_wrapper_classes = array_filter(
365 array(
366 'wp-block-jetpack-subscriptions__supports-newline' => true,
367 'wp-block-jetpack-subscriptions__use-newline' => (bool) get_attribute( $attributes, 'buttonOnNewLine' ),
368 'wp-block-jetpack-subscriptions__show-subs' => (bool) get_attribute( $attributes, 'showSubscribersTotal' ),
369 )
370 );
371
372 return array(
373 'block_wrapper' => implode( ' ', array_keys( $block_wrapper_classes ) ),
374 'email_field' => implode( ' ', array_keys( $email_field_classes ) ),
375 'submit_button' => implode( ' ', array_keys( $submit_button_classes ) ),
376 );
377 }
378
379 /**
380 * Uses block attributes to generate an array containing the styles for various block elements.
381 * Based on Jetpack_Subscriptions_Widget::do_subscription_form() which the block was originally using.
382 *
383 * @param array $attributes Array containing the block attributes.
384 *
385 * @return array
386 */
387 function get_element_styles_from_attributes( $attributes ) {
388 $button_background_style = ! has_attribute( $attributes, 'buttonBackgroundColor' ) && has_attribute( $attributes, 'customButtonGradient' )
389 ? get_attribute( $attributes, 'customButtonGradient' )
390 : get_attribute( $attributes, 'customButtonBackgroundColor' );
391
392 $email_field_styles = '';
393 $submit_button_wrapper_styles = '';
394 $submit_button_styles = '';
395
396 if ( ! empty( $button_background_style ) ) {
397 $submit_button_styles .= sprintf( 'background: %s;', $button_background_style );
398 }
399
400 if ( has_attribute( $attributes, 'customTextColor' ) ) {
401 $submit_button_styles .= sprintf( 'color: %s;', get_attribute( $attributes, 'customTextColor' ) );
402 }
403
404 if ( has_attribute( $attributes, 'buttonWidth' ) ) {
405 $submit_button_wrapper_styles .= sprintf( 'width: %s;', get_attribute( $attributes, 'buttonWidth' ) );
406 $submit_button_wrapper_styles .= 'max-width: 100%;';
407
408 // Account for custom margins on inline forms.
409 $submit_button_styles .= true === get_attribute( $attributes, 'buttonOnNewLine' )
410 ? sprintf( 'width: calc(100%% - %dpx);', get_attribute( $attributes, 'spacing', DEFAULT_SPACING_VALUE ) )
411 : 'width: 100%;';
412 }
413
414 $font_size = get_attribute( $attributes, 'customFontSize', DEFAULT_FONTSIZE_VALUE );
415 $style = sprintf( 'font-size: %s%s;', $font_size, is_numeric( $font_size ) ? 'px' : '' );
416
417 $submit_button_styles .= $style;
418 $email_field_styles .= $style;
419
420 $padding = get_attribute( $attributes, 'padding', DEFAULT_PADDING_VALUE );
421 $style = sprintf( 'padding: %1$dpx %2$dpx %1$dpx %2$dpx;', $padding, round( $padding * 1.5 ) );
422
423 $submit_button_styles .= $style;
424 $email_field_styles .= $style;
425
426 $button_spacing = get_attribute( $attributes, 'spacing', DEFAULT_SPACING_VALUE );
427 if ( true === get_attribute( $attributes, 'buttonOnNewLine' ) ) {
428 $submit_button_styles .= sprintf( 'margin-top: %dpx;', $button_spacing );
429 } else {
430 $submit_button_styles .= 'margin: 0px; '; // Reset Safari's 2px default margin for buttons affecting input and button union
431 $submit_button_styles .= sprintf( 'margin-left: %dpx;', $button_spacing );
432 }
433
434 if ( has_attribute( $attributes, 'borderColor' ) ) {
435 $style = sprintf( 'border-color: %s;', get_attribute( $attributes, 'borderColor', '' ) );
436 $submit_button_styles .= $style;
437 $email_field_styles .= $style;
438 }
439
440 $style = sprintf( 'border-radius: %dpx;', get_attribute( $attributes, 'borderRadius', DEFAULT_BORDER_RADIUS_VALUE ) );
441 $submit_button_styles .= $style;
442 $email_field_styles .= $style;
443
444 $style = sprintf( 'border-width: %dpx;', get_attribute( $attributes, 'borderWeight', DEFAULT_BORDER_WEIGHT_VALUE ) );
445 $submit_button_styles .= $style;
446 $email_field_styles .= $style;
447
448 if ( has_attribute( $attributes, 'customBorderColor' ) ) {
449 $style = sprintf( 'border-color: %s; border-style: solid;', get_attribute( $attributes, 'customBorderColor' ) );
450
451 $submit_button_styles .= $style;
452 $email_field_styles .= $style;
453 }
454
455 if ( ! jetpack_is_frontend() ) {
456 $background_color_style = get_attribute_color( 'buttonBackgroundColor', $attributes, '#113AF5' /* default lettre theme color */ );
457 $text_color_style = get_attribute_color( 'textColor', $attributes, '#FFFFFF' );
458 $submit_button_styles .= sprintf( ' background-color: %s; color: %s;', $background_color_style, $text_color_style );
459 }
460
461 return array(
462 'email_field' => $email_field_styles,
463 'submit_button' => $submit_button_styles,
464 'submit_button_wrapper' => $submit_button_wrapper_styles,
465 );
466 }
467
468 /**
469 * Retrieve the resolved color for a given attribute.
470 *
471 * @param string $attribute_name The name of the attribute to resolve.
472 * @param array $attributes An array of all attributes.
473 * @param string $default_color A fallback color in case no color can be resolved.
474 *
475 * @return string Returns the resolved color or the default color if no color is found.
476 */
477 function get_attribute_color( $attribute_name, $attributes, $default_color ) {
478 if ( has_attribute( $attributes, $attribute_name ) ) {
479 $color_slug = get_attribute( $attributes, $attribute_name );
480 $resolved_color = get_color_from_slug( $color_slug );
481
482 if ( $resolved_color ) {
483 return $resolved_color;
484 }
485 }
486
487 return get_global_style_color( $attribute_name, $default_color );
488 }
489
490 /**
491 * Retrieve the global style color based on a provided style key.
492 *
493 * @param string $style_key The key for the desired style.
494 * @param string $default_color A fallback color in case the global style is not set.
495 *
496 * @return string Returns the color defined in global styles or the default color if not defined.
497 */
498 function get_global_style_color( $style_key, $default_color ) {
499 $global_styles = wp_get_global_styles(
500 array( 'color' ),
501 array(
502 'block_name' => 'core/button',
503 'transforms' => array( 'resolve-variables' ),
504 )
505 );
506
507 if ( isset( $global_styles[ $style_key ] ) ) {
508 return $global_styles[ $style_key ];
509 }
510
511 return $default_color;
512 }
513
514 /**
515 * Convert a color slug into its corresponding color value.
516 *
517 * @param string $slug The slug representation of the color.
518 *
519 * @return string|null Returns the color value if found, or null otherwise.
520 */
521 function get_color_from_slug( $slug ) {
522 $color_palettes = wp_get_global_settings( array( 'color', 'palette' ) );
523
524 if ( ! is_array( $color_palettes ) ) {
525 return null;
526 }
527
528 foreach ( $color_palettes as $palette ) {
529 if ( is_array( $palette ) ) {
530 foreach ( $palette as $color ) {
531 if ( isset( $color['slug'] ) && $color['slug'] === $slug && isset( $color['color'] ) ) {
532 return $color['color'];
533 }
534 }
535 }
536 }
537
538 return null;
539 }
540
541 /**
542 * Subscriptions block render callback.
543 *
544 * @param array $attributes Array containing the block attributes.
545 *
546 * @return string
547 */
548 function render_block( $attributes ) {
549 // If the Subscriptions module is not active, don't render the block.
550 if ( ! Jetpack::is_module_active( 'subscriptions' ) ) {
551 return '';
552 }
553
554 if ( class_exists( '\Jetpack_Memberships' ) ) {
555 // We only want the sites that have newsletter feature enabled to be graced by this JavaScript.
556 Jetpack_Gutenberg::load_assets_as_required( __DIR__ );
557 } else {
558 Jetpack_Gutenberg::load_styles_as_required( FEATURE_NAME );
559 }
560
561 $subscribe_email = Jetpack_Memberships::get_current_user_email();
562
563 /** This filter is documented in modules/contact-form/grunion-contact-form.php */
564 if ( is_wpcom() || false !== apply_filters( 'jetpack_auto_fill_logged_in_user', false ) ) {
565 $current_user = wp_get_current_user();
566 $subscribe_email = ! empty( $current_user->user_email ) ? $current_user->user_email : '';
567 }
568
569 // The block is using the Jetpack_Subscriptions_Widget backend, hence the need to increase the instance count.
570 ++Jetpack_Subscriptions_Widget::$instance_count;
571
572 $classes = get_element_class_names_from_attributes( $attributes );
573 $styles = get_element_styles_from_attributes( $attributes );
574
575 // The default value was previously "true" in block.json. We don't want to rely setting "default" in block.json to falsy,
576 // because it would change the setting for previously saved blocks. Block editor doesn't store default values in attributes at all.
577 // Hence users without this set will still get social counts included in the subscriber counter.
578 // Lowering the subscriber count on their behalf with code change would be controversial.
579 // We want to disencourage including social count as it's misleading.
580 $include_social_followers = isset( $attributes['includeSocialFollowers'] ) ? (bool) get_attribute( $attributes, 'includeSocialFollowers' ) : true;
581
582 $data = array(
583 'widget_id' => Jetpack_Subscriptions_Widget::$instance_count,
584 'subscribe_email' => $subscribe_email,
585 'is_paid_subscriber' => get_attribute( $attributes, 'isPaidSubscriber', false ),
586 'wrapper_attributes' => get_block_wrapper_attributes(
587 array(
588 'class' => $classes['block_wrapper'],
589 )
590 ),
591 'subscribe_placeholder' => get_attribute( $attributes, 'subscribePlaceholder', __( 'Type your email…', 'jetpack' ) ),
592 'submit_button_text' => get_attribute( $attributes, 'submitButtonText', __( 'Subscribe', 'jetpack' ) ),
593 'submit_button_text_subscribed' => get_attribute( $attributes, 'submitButtonTextSubscribed', __( 'Subscribed', 'jetpack' ) ),
594 'submit_button_text_upgrade' => get_attribute( $attributes, 'submitButtonTextUpgrade', __( 'Upgrade subscription', 'jetpack' ) ),
595 'success_message' => get_attribute(
596 $attributes,
597 'successMessage',
598 esc_html__( "Success! An email was just sent to confirm your subscription. Please find the email now and click 'Confirm Follow' to start subscribing.", 'jetpack' )
599 ),
600 'show_subscribers_total' => (bool) get_attribute( $attributes, 'showSubscribersTotal' ),
601 'subscribers_total' => get_subscriber_count( $include_social_followers ),
602 'referer' => esc_url_raw(
603 ( is_ssl() ? 'https' : 'http' ) . '://' . ( isset( $_SERVER['HTTP_HOST'] ) ? wp_unslash( $_SERVER['HTTP_HOST'] ) : '' ) .
604 ( isset( $_SERVER['REQUEST_URI'] ) ? wp_unslash( $_SERVER['REQUEST_URI'] ) : '' )
605 ),
606 'source' => 'subscribe-block',
607 'app_source' => get_attribute( $attributes, 'appSource', null ),
608 );
609
610 if ( ! jetpack_is_frontend() ) {
611 return render_for_email( $data, $styles );
612 }
613
614 return render_for_website( $data, $classes, $styles );
615 }
616
617 /**
618 * Get the post access level for the current post. Defaults to 'everybody' if the query is not for a single post
619 *
620 * @return string the actual post access level (see projects/plugins/jetpack/extensions/blocks/subscriptions/constants.js for the values).
621 */
622 function get_post_access_level_for_current_post() {
623 if ( ! is_singular() ) {
624 // There is no "actual" current post.
625 return Abstract_Token_Subscription_Service::POST_ACCESS_LEVEL_EVERYBODY;
626 }
627
628 return Jetpack_Memberships::get_post_access_level();
629 }
630
631 /**
632 * Renders the subscriptions block at the site.
633 *
634 * @param array $data Array containing block view data.
635 * @param array $classes Array containing the classes for different block elements.
636 * @param array $styles Array containing the styles for different block elements.
637 *
638 * @return string
639 */
640 function render_for_website( $data, $classes, $styles ) {
641 $lang = get_locale();
642 $blog_id = \Jetpack_Options::get_option( 'id' );
643 $widget_id_suffix = Jetpack_Subscriptions_Widget::$instance_count > 1 ? '-' . Jetpack_Subscriptions_Widget::$instance_count : '';
644 $form_id = 'subscribe-blog' . $widget_id_suffix;
645 $form_url = 'https://wordpress.com/email-subscriptions';
646 $post_access_level = get_post_access_level_for_current_post();
647
648 // Post ID is used for pulling post-specific paid status, and returning to the right post after confirming subscription
649 $post_id = null;
650 if ( in_the_loop() ) {
651 $post_id = get_the_ID();
652 } elseif ( is_singular( 'post' ) || is_page() ) {
653 $post_id = get_queried_object_id();
654 } else {
655 $post_id = get_option( 'page_on_front' );
656 }
657
658 $subscribe_field_id = apply_filters( 'subscribe_field_id', 'subscribe-field' . $widget_id_suffix, $data['widget_id'] );
659 $tier_id = get_post_meta( $post_id, META_NAME_FOR_POST_TIER_ID_SETTINGS, true );
660 $is_subscribed = Jetpack_Memberships::is_current_user_subscribed();
661 $button_text = get_submit_button_text( $data );
662
663 ob_start();
664
665 Jetpack_Subscriptions_Widget::render_widget_status_messages(
666 array(
667 'success_message' => $data['success_message'],
668 )
669 );
670 ?>
671 <div <?php echo wp_kses_data( $data['wrapper_attributes'] ); ?>>
672 <div class="wp-block-jetpack-subscriptions__container<?php echo ! $is_subscribed ? ' is-not-subscriber' : ''; ?>">
673 <form
674 action="<?php echo esc_url( $form_url ); ?>"
675 method="post"
676 accept-charset="utf-8"
677 data-blog="<?php echo esc_attr( $blog_id ); ?>"
678 data-post_access_level="<?php echo esc_attr( $post_access_level ); ?>"
679 data-subscriber_email="<?php echo esc_attr( $data['subscribe_email'] ); ?>"
680 id="<?php echo esc_attr( $form_id ); ?>"
681 >
682 <div class="wp-block-jetpack-subscriptions__form-elements">
683 <?php if ( ! $is_subscribed ) : ?>
684 <p id="subscribe-email">
685 <label
686 id="<?php echo esc_attr( $subscribe_field_id . '-label' ); ?>"
687 for="<?php echo esc_attr( $subscribe_field_id ); ?>"
688 class="screen-reader-text"
689 >
690 <?php echo esc_html( $data['subscribe_placeholder'] ); ?>
691 </label>
692 <?php
693 printf(
694 '<input
695 required="required"
696 type="email"
697 name="email"
698 %1$s
699 style="%2$s"
700 placeholder="%3$s"
701 value="%4$s"
702 id="%5$s"
703 %6$s
704 />',
705 ( ! empty( $classes['email_field'] )
706 ? 'class="' . esc_attr( $classes['email_field'] ) . '"'
707 : ''
708 ),
709 ( ! empty( $styles['email_field'] )
710 ? esc_attr( $styles['email_field'] )
711 : 'width: 95%; padding: 1px 10px'
712 ),
713 esc_attr( $data['subscribe_placeholder'] ),
714 esc_attr( $data['subscribe_email'] ),
715 esc_attr( $subscribe_field_id ),
716 ( ! empty( $data['subscribe_email'] )
717 ? 'disabled title="' . esc_attr__( "You're logged in with this email", 'jetpack' ) . '"'
718 : ''
719 )
720 );
721 ?>
722 </p>
723 <?php endif; ?>
724 <p id="subscribe-submit"
725 <?php if ( ! empty( $styles['submit_button_wrapper'] ) ) : ?>
726 style="<?php echo esc_attr( $styles['submit_button_wrapper'] ); ?>"
727 <?php endif; ?>
728 >
729 <input type="hidden" name="action" value="<?php echo is_top_subscription() ? 'subscribed' : 'subscribe'; ?>"/>
730 <input type="hidden" name="blog_id" value="<?php echo (int) $blog_id; ?>"/>
731 <input type="hidden" name="source" value="<?php echo esc_url( $data['referer'] ); ?>"/>
732 <input type="hidden" name="sub-type" value="<?php echo esc_attr( $data['source'] ); ?>"/>
733 <input type="hidden" name="app_source" value="<?php echo esc_attr( $data['app_source'] ); ?>"/>
734 <input type="hidden" name="redirect_fragment" value="<?php echo esc_attr( $form_id ); ?>"/>
735 <input type="hidden" name="lang" value="<?php echo esc_attr( $lang ); ?>"/>
736 <?php
737 wp_nonce_field( 'blogsub_subscribe_' . $blog_id );
738
739 if ( ! empty( $post_id ) ) {
740 echo '<input type="hidden" name="post_id" value="' . esc_attr( $post_id ) . '"/>';
741 }
742
743 if ( ! empty( $tier_id ) ) {
744 echo '<input type="hidden" name="tier_id" value="' . esc_attr( $tier_id ) . '"/>';
745 }
746 ?>
747 <button type="submit"
748 <?php if ( ! empty( $classes['submit_button'] ) ) : ?>
749 class="<?php echo esc_attr( $classes['submit_button'] ); ?>"
750 <?php endif; ?>
751 <?php if ( ! empty( $styles['submit_button'] ) ) : ?>
752 style="<?php echo esc_attr( $styles['submit_button'] ); ?>"
753 <?php endif; ?>
754 name="jetpack_subscriptions_widget"
755 >
756 <?php echo sanitize_submit_text( $button_text ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
757 </button>
758 </p>
759 </div>
760 </form>
761 <?php if ( $data['show_subscribers_total'] && $data['subscribers_total'] ) : ?>
762 <div class="wp-block-jetpack-subscriptions__subscount">
763 <?php
764 echo esc_html( Jetpack_Memberships::get_join_others_text( $data['subscribers_total'] ) );
765 ?>
766 </div>
767 <?php endif; ?>
768 </div>
769 </div>
770 <?php
771 return ob_get_clean();
772 }
773
774 /**
775 * Renders the email version of the subscriptions block.
776 *
777 * @param array $data Array containing block view data.
778 * @param array $styles Array containing the styles for different block elements.
779 *
780 * @return string
781 */
782 function render_for_email( $data, $styles ) {
783 $submit_button_wrapper_style = ! empty( $styles['submit_button_wrapper'] ) ? 'style="' . esc_attr( $styles['submit_button_wrapper'] ) . '"' : '';
784 $button_text = get_submit_button_text( $data );
785
786 $html = '<div ' . wp_kses_data( $data['wrapper_attributes'] ) . '>
787 <div>
788 <div>
789 <div>
790 <p ' . $submit_button_wrapper_style . '>
791 <a href="' . esc_url( get_post_permalink() ) . '" style="' . esc_attr( $styles['submit_button'] ) . ' text-decoration: none; white-space: nowrap; margin-left: 0">' . sanitize_submit_text( $button_text ) . '</a>
792 </p>
793 </div>
794 </div>
795 </div>
796 </div>';
797
798 return $html;
799 }
800
801 /**
802 * Filter excerpts looking for subscription data.
803 *
804 * @param string $excerpt The extrapolated excerpt string.
805 * @param \WP_Post $post The current post being processed (in `get_the_excerpt`).
806 *
807 * @return mixed
808 */
809 function jetpack_filter_excerpt_for_newsletter( $excerpt, $post = null ) {
810 // The blogmagazine theme is overriding WP core `get_the_excerpt` filter and only passing the excerpt
811 // TODO: Until this is fixed, return the excerpt without gating. See https://github.com/Automattic/jetpack/pull/28102#issuecomment-1369161116
812 if ( $post && str_contains( $post->post_content, '<!-- wp:jetpack/subscriptions -->' ) ) {
813 $excerpt .= sprintf(
814 // translators: %s is the permalink url to the current post.
815 __( "<p><a href='%s'>View post</a> to subscribe to site newsletter.</p>", 'jetpack' ),
816 get_post_permalink()
817 );
818 }
819 return $excerpt;
820 }
821
822 /**
823 * Gate access to posts
824 *
825 * @param string $the_content Post content.
826 *
827 * @return string
828 */
829 function add_paywall( $the_content ) {
830 require_once JETPACK__PLUGIN_DIR . 'modules/memberships/class-jetpack-memberships.php';
831
832 $post_access_level = Jetpack_Memberships::get_post_access_level();
833
834 if ( Jetpack_Memberships::user_can_view_post() ) {
835 if ( $post_access_level !== Abstract_Token_Subscription_Service::POST_ACCESS_LEVEL_EVERYBODY ) {
836 do_action(
837 'earn_track_paywalled_post_view',
838 array(
839 'post_id' => get_the_ID(),
840 )
841 );
842 }
843 return $the_content;
844 }
845
846 $paywalled_content = get_paywall_content( $post_access_level ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
847
848 if ( has_block( \Automattic\Jetpack\Extensions\Paywall\BLOCK_NAME ) ) {
849 if ( strpos( $the_content, \Automattic\Jetpack\Extensions\Paywall\BLOCK_HTML ) ) {
850 return strstr( $the_content, \Automattic\Jetpack\Extensions\Paywall\BLOCK_HTML, true ) . $paywalled_content;
851 }
852 // WordPress generates excerpts by either rendering or stripping blocks before invoking the `the_content` filter.
853 // In the context of generating an excerpt, the Paywall block specifically renders THE_EXCERPT_BLOCK.
854 if ( strpos( $the_content, \Automattic\Jetpack\Extensions\Paywall\THE_EXCERPT_BLOCK ) ) {
855 return strstr( $the_content, \Automattic\Jetpack\Extensions\Paywall\THE_EXCERPT_BLOCK, true );
856 }
857 }
858
859 return $paywalled_content;
860 }
861
862 /**
863 * Gate access to comments. We want to close comments on private sites.
864 *
865 * @param bool $default_comments_open Default state of the comments_open filter.
866 * @param int $post_id Current post id.
867 *
868 * @return bool
869 */
870 function maybe_close_comments( $default_comments_open, $post_id ) {
871 if ( ! $default_comments_open || ! $post_id ) {
872 return $default_comments_open;
873 }
874
875 require_once JETPACK__PLUGIN_DIR . 'modules/memberships/class-jetpack-memberships.php';
876 return Jetpack_Memberships::user_can_view_post();
877 }
878
879 /**
880 * Gate access to existing comments
881 *
882 * @param string $comment The comment.
883 *
884 * @return string
885 */
886 function maybe_gate_existing_comments( $comment ) {
887 if ( empty( $comment ) ) {
888 return $comment;
889 }
890
891 require_once JETPACK__PLUGIN_DIR . 'modules/memberships/class-jetpack-memberships.php';
892 if ( Jetpack_Memberships::user_can_view_post() ) {
893 return $comment;
894 }
895 return '';
896 }
897
898 /**
899 * Returns paywall content blocks
900 *
901 * @param string $post_access_level The newsletter access level.
902 * @return string
903 */
904 function get_paywall_content( $post_access_level ) {
905 if ( Jetpack_Memberships::user_is_pending_subscriber() ) {
906 return get_paywall_blocks_subscribe_pending();
907 }
908 if ( doing_filter( 'get_the_excerpt' ) ) {
909 return '';
910 }
911 return get_paywall_blocks( $post_access_level );
912 }
913
914 /**
915 * Returns the current URL.
916 *
917 * TODO: Copied from https://github.com/Automattic/jetpack/blob/bb885061dc3ee7a80a78a5f0116ab3fcebfddb09/projects/packages/boost-core/src/lib/class-url.php#L39
918 * TODO: Move to a shared package
919 *
920 * @return string
921 */
922 function get_current_url() {
923 // Fallback to the site URL if we're unable to determine the URL from $_SERVER global.
924 $current_url = site_url();
925
926 if ( isset( $_SERVER ) && is_array( $_SERVER ) ) {
927 // phpcs:disable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitization happens at the end
928 $scheme = isset( $_SERVER['HTTPS'] ) && 'on' === $_SERVER['HTTPS'] ? 'https' : 'http';
929 $host = ! empty( $_SERVER['HTTP_HOST'] ) ? wp_unslash( $_SERVER['HTTP_HOST'] ) : null;
930 $path = ! empty( $_SERVER['REQUEST_URI'] ) ? wp_unslash( $_SERVER['REQUEST_URI'] ) : '';
931
932 // Support for local plugin development and testing using ngrok.
933 if ( ! empty( $_SERVER['HTTP_X_ORIGINAL_HOST'] ) && str_contains( $_SERVER['HTTP_X_ORIGINAL_HOST'], 'ngrok.io' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- This is validating.
934 $host = wp_unslash( $_SERVER['HTTP_X_ORIGINAL_HOST'] );
935 }
936 // phpcs:enable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
937
938 if ( $host ) {
939 $current_url = esc_url_raw( sprintf( '%s://%s%s', $scheme, $host, $path ) );
940 }
941 }
942
943 return $current_url;
944 }
945
946 /**
947 * Get the submit button text based on the subscription status.
948 *
949 * @param array $data Array containing block view data.
950 *
951 * @return string
952 */
953 function get_submit_button_text( $data ) {
954 if ( ! Jetpack_Memberships::is_current_user_subscribed() ) {
955 return $data['submit_button_text'];
956 }
957 if ( ! Jetpack_Memberships::user_can_view_post() ) {
958 return $data['submit_button_text_upgrade'];
959 }
960 return '✓ ' . $data['submit_button_text_subscribed'];
961 }
962
963 /**
964 * Returns true if there are no more tiers to upgrade to.
965 *
966 * @return boolean
967 */
968 function is_top_subscription() {
969 if ( ! Jetpack_Memberships::is_current_user_subscribed() ) {
970 return false;
971 }
972 if ( ! Jetpack_Memberships::user_can_view_post() ) {
973 return false;
974 }
975 return true;
976 }
977
978 /**
979 * Sanitize the submit button text.
980 *
981 * @param string $text String containing the submit button text.
982 *
983 * @return string
984 */
985 function sanitize_submit_text( $text ) {
986 return wp_kses(
987 html_entity_decode( $text, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 ),
988 Jetpack_Subscriptions_Widget::$allowed_html_tags_for_submit_button
989 );
990 }
991
992 /**
993 * Returns paywall content blocks if user is not authenticated
994 *
995 * @param string $newsletter_access_level The newsletter access level.
996 * @return string
997 */
998 function get_paywall_blocks( $newsletter_access_level ) {
999 $custom_paywall = apply_filters( 'jetpack_custom_paywall_blocks', false );
1000 if ( ! empty( $custom_paywall ) ) {
1001 return $custom_paywall;
1002 }
1003 if ( ! jetpack_is_frontend() ) { // emails
1004 return get_paywall_simple();
1005 }
1006 require_once JETPACK__PLUGIN_DIR . 'modules/memberships/class-jetpack-memberships.php';
1007 // Only display paid texts when Stripe is connected and the post is marked for paid subscribers
1008 $is_paid_post = $newsletter_access_level === 'paid_subscribers' && Jetpack_Memberships::has_connected_account();
1009 $is_paid_subscriber = Jetpack_Memberships::user_is_paid_subscriber();
1010
1011 $access_heading = $is_paid_subscriber
1012 ? esc_html__( 'Upgrade to continue reading', 'jetpack' )
1013 : esc_html__( 'Subscribe to continue reading', 'jetpack' );
1014
1015 $subscribe_text = $is_paid_post
1016 // translators: %s is the name of the site.
1017 ? $is_paid_subscriber
1018 ? esc_html__( 'Upgrade to get access to the rest of this post and other exclusive content.', 'jetpack' )
1019 : esc_html__( 'Become a paid subscriber to get access to the rest of this post and other exclusive content.', 'jetpack' )
1020 // translators: %s is the name of the site.
1021 : esc_html__( 'Subscribe to get access to the rest of this post and other subscriber-only content.', 'jetpack' );
1022
1023 $sign_in = '';
1024 $switch_accounts = '';
1025
1026 if ( ( new Host() )->is_wpcom_simple() ) {
1027 // On WPCOM we will redirect directly to the current page
1028 $redirect_url = get_current_url();
1029 } else {
1030 // On self-hosted we will save and hide the token
1031 $redirect_url = get_site_url() . '/wp-json/jetpack/v4/subscribers/auth';
1032 $redirect_url = add_query_arg( 'redirect_url', get_current_url(), $redirect_url );
1033 }
1034
1035 $sign_in_link = add_query_arg(
1036 array(
1037 'site_id' => intval( \Jetpack_Options::get_option( 'id' ) ),
1038 'redirect_url' => rawurlencode( $redirect_url ),
1039 ),
1040 'https://subscribe.wordpress.com/memberships/jwt'
1041 );
1042 if ( is_user_auth() ) {
1043 if ( ( new Host() )->is_wpcom_simple() ) {
1044 $switch_accounts_link = wp_logout_url( $sign_in_link );
1045 $switch_accounts = '<!-- wp:paragraph {"align":"center","style":{"typography":{"fontSize":"14px"}}} -->
1046 <p class="has-text-align-center" style="font-size:14px"><a href="' . $switch_accounts_link . '">' . __( 'Switch Accounts', 'jetpack' ) . '</a></p>
1047 <!-- /wp:paragraph -->';
1048
1049 }
1050 } else {
1051 if ( ( new Host() )->is_wpcom_simple() ) {
1052 // custom domain
1053 $sign_in_link = wpcom_logmein_redirect_url( get_current_url(), false, null, 'link', get_current_blog_id() );
1054 }
1055 $access_question = get_paywall_access_question( $newsletter_access_level );
1056 $sign_in = '<!-- wp:paragraph {"align":"center","style":{"typography":{"fontSize":"14px"}}} -->
1057 <p class="has-text-align-center" style="font-size:14px"><a href="' . $sign_in_link . '">' . $access_question . '</a></p>
1058 <!-- /wp:paragraph -->';
1059 }
1060
1061 $lock_svg = plugins_url( 'images/lock-paywall.svg', JETPACK__PLUGIN_FILE );
1062
1063 return '
1064 <!-- wp:group {"style":{"border":{"width":"1px","radius":"4px"},"spacing":{"padding":{"top":"32px","bottom":"32px","left":"32px","right":"32px"}}},"borderColor":"primary","className":"jetpack-subscribe-paywall","layout":{"type":"constrained","contentSize":"400px"}} -->
1065 <div class="wp-block-group jetpack-subscribe-paywall has-border-color has-primary-border-color" style="border-width:1px;border-radius:4px;padding-top:32px;padding-right:32px;padding-bottom:32px;padding-left:32px">
1066 <!-- wp:image {"align":"center","width":24,"height":24,"sizeSlug":"large","linkDestination":"none"} -->
1067 <figure class="wp-block-image aligncenter size-large is-resized"><img src="' . $lock_svg . '" alt="" width="24" height="24"/></figure>
1068 <!-- /wp:image -->
1069
1070 <!-- wp:heading {"textAlign":"center","style":{"typography":{"fontStyle":"normal","fontWeight":"600","fontSize":"24px"},"layout":{"selfStretch":"fit"}}} -->
1071 <h2 class="wp-block-heading has-text-align-center" style="font-size:24px;font-style:normal;font-weight:600">' . $access_heading . '</h2>
1072 <!-- /wp:heading -->
1073
1074 <!-- wp:paragraph {"align":"center","style":{"typography":{"fontSize":"14px"},"spacing":{"margin":{"top":"10px","bottom":"10px"}}}} -->
1075 <p class="has-text-align-center" style="margin-top:10px;margin-bottom:10px;font-size:14px">' . $subscribe_text . '</p>
1076 <!-- /wp:paragraph -->
1077
1078 <!-- wp:jetpack/subscriptions {"borderRadius":50,"borderColor":"primary","className":"is-style-compact","isPaidSubscriber":' . ( $is_paid_subscriber ? 'true' : 'false' ) . '} /-->
1079 ' . $sign_in . '
1080 ' . $switch_accounts . '
1081 </div>
1082 <!-- /wp:group -->
1083 ';
1084 }
1085
1086 /**
1087 * Returns Get Access question for the paywall
1088 *
1089 * @param string $post_access_level The newsletter access level.
1090 * @return string.
1091 */
1092 function get_paywall_access_question( $post_access_level ) {
1093 switch ( $post_access_level ) {
1094 case Abstract_Token_Subscription_Service::POST_ACCESS_LEVEL_PAID_SUBSCRIBERS:
1095 case Abstract_Token_Subscription_Service::POST_ACCESS_LEVEL_PAID_SUBSCRIBERS_ALL_TIERS:
1096 $tier = Jetpack_Memberships::get_post_tier();
1097 if ( $tier !== null ) {
1098 return sprintf(
1099 // translators: Placeholder is the tier name
1100 __( 'Already a higher-tier paid subscriber?', 'jetpack' ),
1101 esc_html( $tier->post_title )
1102 );
1103 } else {
1104 return esc_html__( 'Already a paid subscriber?', 'jetpack' );
1105 }
1106 default:
1107 return esc_html__( 'Already a subscriber?', 'jetpack' );
1108 }
1109 }
1110
1111 /**
1112 * Returns true if user is auth for subscriptions check, otherwise returns false.
1113 *
1114 * @return boolean
1115 */
1116 function is_user_auth() {
1117 if ( ( new Host() )->is_wpcom_simple() && is_user_logged_in() ) {
1118 return true;
1119 }
1120 if ( current_user_can( 'manage_options' ) ) {
1121 return true;
1122 }
1123 if ( class_exists( 'Automattic\Jetpack\Extensions\Premium_Content\Subscription_Service\Jetpack_Token_Subscription_Service' ) ) {
1124 if ( Jetpack_Token_Subscription_Service::has_token_from_cookie() ) {
1125 return true;
1126 }
1127 }
1128 return false;
1129 }
1130
1131 /**
1132 * Returns paywall content blocks when email confirmation is pending
1133 *
1134 * @return string
1135 */
1136 function get_paywall_blocks_subscribe_pending() {
1137 $subscribe_email = Jetpack_Memberships::get_current_user_email();
1138
1139 /** This filter is documented in modules/contact-form/grunion-contact-form.php */
1140 if ( is_wpcom() || false !== apply_filters( 'jetpack_auto_fill_logged_in_user', false ) ) {
1141 $current_user = wp_get_current_user();
1142 $subscribe_email = ! empty( $current_user->user_email ) ? $current_user->user_email : '';
1143 }
1144
1145 $access_heading = esc_html__( 'Confirm your subscription to continue reading', 'jetpack' );
1146
1147 /* translators: %s: email address */
1148 $subscribe_text = sprintf( esc_html__( 'Head to your inbox and confirm your email address %s.', 'jetpack' ), $subscribe_email );
1149
1150 $lock_svg = plugins_url( 'images/lock-paywall.svg', JETPACK__PLUGIN_FILE );
1151
1152 return '
1153 <!-- wp:group {"style":{"border":{"width":"1px","radius":"4px"},"spacing":{"padding":{"top":"32px","bottom":"32px","left":"32px","right":"32px"}}},"borderColor":"primary","className":"jetpack-subscribe-paywall","layout":{"type":"constrained","contentSize":"400px"}} -->
1154 <div class="wp-block-group jetpack-subscribe-paywall has-border-color has-primary-border-color" style="border-width:1px;border-radius:4px;padding-top:32px;padding-right:32px;padding-bottom:32px;padding-left:32px">
1155 <!-- wp:image {"align":"center","width":24,"height":24,"sizeSlug":"large","linkDestination":"none"} -->
1156 <figure class="wp-block-image aligncenter size-large is-resized"><img src="' . $lock_svg . '" alt="" width="24" height="24"/></figure>
1157 <!-- /wp:image -->
1158
1159 <!-- wp:heading {"textAlign":"center","style":{"typography":{"fontStyle":"normal","fontWeight":"600","fontSize":"24px", "maxWidth":"initial"},"layout":{"selfStretch":"fit"}}} -->
1160 <h2 class="wp-block-heading has-text-align-center" style="font-size:24px;font-style:normal;font-weight:600;max-width:initial">' . $access_heading . '</h2>
1161 <!-- /wp:heading -->
1162
1163 <!-- wp:paragraph {"align":"center","style":{"typography":{"fontSize":"14px"},"spacing":{"margin":{"top":"10px","bottom":"10px"}}}} -->
1164 <p class="has-text-align-center" style="margin-top:10px;margin-bottom:10px;font-size:14px">' . $subscribe_text . '</p>
1165 <!-- /wp:paragraph -->
1166 </div>
1167 <!-- /wp:group -->
1168 ';
1169 }
1170
1171 /**
1172 * Return content for non frontend views like emails.
1173 *
1174 * @return string
1175 */
1176 function get_paywall_simple() {
1177 $access_heading = esc_html__( "You're currently a free subscriber. Upgrade your subscription to get access to the rest of this post and other paid-subscriber only content.", 'jetpack' );
1178
1179 $subscribe_text = esc_html__( 'Upgrade subscription', 'jetpack' );
1180
1181 return '
1182 <!-- wp:columns -->
1183 <div class="wp-block-columns" style="display: inline-block; width: 90%">
1184 <!-- wp:column -->
1185 <div class="wp-block-column" style="background-color: #F6F7F7; padding: 32px; 24px;">
1186 <!-- wp:paragraph -->
1187 <p class="has-text-align-center"
1188 style="text-align: center;
1189 color: #50575E;
1190 font-weight: 400;
1191 font-size: 16px;
1192 font-family: \'SF Pro Text\', sans-serif;
1193 line-height: 28.8px;">
1194 ' . $access_heading . '
1195 </p>
1196 <!-- /wp:paragraph -->
1197
1198 <!-- wp:buttons -->
1199 <div class="wp-block-buttons" style="text-align: center;">
1200 <!-- wp:button -->
1201 <div class="wp-block-button" style="display: inline-block; margin: 10px 0;">
1202 <a href="' . esc_url( get_post_permalink() ) . '" class="wp-block-button__link wp-element-button"
1203 data-wpcom-track data-tracks-link-desc="paywall-email-click"
1204 style="display: inline-block;
1205 padding: 15px 20px;
1206 background-color: #0675C4;
1207 color: #FFFFFF;
1208 text-decoration: none;
1209 border-radius: 5px;
1210 font-family: \'SF Pro Display\', sans-serif;
1211 font-weight: 500;
1212 font-size: 16px;
1213 text-align: center;">' . $subscribe_text . '</a>
1214 </div>
1215 <!-- /wp:button -->
1216 </div>
1217 <!-- /wp:buttons -->
1218 </div>
1219 <!-- /wp:column -->
1220 </div>
1221 <!-- /wp:columns -->
1222 ';
1223 }
1224