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