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