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