PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 12.3.2
Jetpack – WP Security, Backup, Speed, & Growth v12.3.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 3 years ago subscriptions.php 3 years ago
subscriptions.php
839 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 Jetpack;
15 use Jetpack_Gutenberg;
16 use Jetpack_Memberships;
17 use Jetpack_Subscriptions_Widget;
18
19 require_once __DIR__ . '/constants.php';
20
21 /**
22 * These block defaults should match ./constants.js
23 */
24 const DEFAULT_BORDER_RADIUS_VALUE = 0;
25 const DEFAULT_BORDER_WEIGHT_VALUE = 1;
26 const DEFAULT_FONTSIZE_VALUE = '16px';
27 const DEFAULT_PADDING_VALUE = 15;
28 const DEFAULT_SPACING_VALUE = 10;
29
30 /**
31 * Registers the block for use in Gutenberg
32 * This is done via an action so that we can disable
33 * registration if we need to.
34 */
35 function register_block() {
36 /*
37 * Disable the feature on P2 blogs
38 */
39 if ( function_exists( '\WPForTeams\is_wpforteams_site' ) &&
40 \WPForTeams\is_wpforteams_site( get_current_blog_id() ) ) {
41 return;
42 }
43
44 if (
45 ( defined( 'IS_WPCOM' ) && IS_WPCOM )
46 || ( ( new Connection_Manager( 'jetpack' ) )->has_connected_owner() && ! ( new Status() )->is_offline_mode() )
47 ) {
48 Blocks::jetpack_register_block(
49 BLOCK_NAME,
50 array(
51 'render_callback' => __NAMESPACE__ . '\render_block',
52 'supports' => array(
53 'spacing' => array(
54 'margin' => true,
55 'padding' => true,
56 ),
57 'align' => array( 'wide', 'full' ),
58 ),
59 )
60 );
61 }
62
63 /*
64 * If the Subscriptions module is not active,
65 * do not make any further changes on the site.
66 */
67 if ( ! Jetpack::is_module_active( 'subscriptions' ) ) {
68 return;
69 }
70
71 /**
72 * Do not proceed if the newsletter feature is not enabled
73 * or if the 'Jetpack_Memberships' class does not exists.
74 */
75 if (
76 /** This filter is documented in class.jetpack-gutenberg.php */
77 ! apply_filters( 'jetpack_subscriptions_newsletter_feature_enabled', true )
78 || ! class_exists( '\Jetpack_Memberships' )
79 ) {
80 return;
81 }
82
83 register_post_meta(
84 'post',
85 META_NAME_FOR_POST_LEVEL_ACCESS_SETTINGS,
86 array(
87 'show_in_rest' => true,
88 'single' => true,
89 'type' => 'string',
90 'auth_callback' => function () {
91 return wp_get_current_user()->has_cap( 'edit_posts' );
92 },
93 )
94 );
95
96 // This ensures Jetpack will sync this post meta to WPCOM.
97 add_filter(
98 'jetpack_sync_post_meta_whitelist',
99 function ( $allowed_meta ) {
100 return array_merge( $allowed_meta, array( META_NAME_FOR_POST_LEVEL_ACCESS_SETTINGS ) );
101 }
102 );
103
104 // Hide the content
105 add_action( 'the_content', __NAMESPACE__ . '\maybe_get_locked_content' );
106
107 // Close comments on the front-end
108 add_filter( 'comments_open', __NAMESPACE__ . '\maybe_close_comments', 10, 2 );
109 add_filter( 'pings_open', __NAMESPACE__ . '\maybe_close_comments', 10, 2 );
110
111 // Hide existing comments
112 add_filter( 'get_comment', __NAMESPACE__ . '\maybe_gate_existing_comments' );
113
114 // Gate the excerpt for a post
115 add_filter( 'get_the_excerpt', __NAMESPACE__ . '\jetpack_filter_excerpt_for_newsletter', 10, 2 );
116
117 // Add a 'Newsletter access' column to the Edit posts page
118 add_action( 'manage_post_posts_columns', __NAMESPACE__ . '\register_newsletter_access_column' );
119 add_action( 'manage_post_posts_custom_column', __NAMESPACE__ . '\render_newsletter_access_rows', 10, 2 );
120 }
121 add_action( 'init', __NAMESPACE__ . '\register_block', 9 );
122
123 /**
124 * Returns true when in a WP.com environment.
125 *
126 * @return boolean
127 */
128 function is_wpcom() {
129 return defined( 'IS_WPCOM' ) && IS_WPCOM;
130 }
131
132 /**
133 * Adds a 'Newsletter' column after the 'Title' column in the post list
134 *
135 * @param array $columns An array of column names.
136 * @return array An array of column names.
137 */
138 function register_newsletter_access_column( $columns ) {
139 $position = array_search( 'title', array_keys( $columns ), true );
140 $new_column = array( NEWSLETTER_COLUMN_ID => '<span>' . __( 'Newsletter', 'jetpack' ) . '</span>' );
141 return array_merge(
142 array_slice( $columns, 0, $position + 1, true ),
143 $new_column,
144 array_slice( $columns, $position, null, true )
145 );
146 }
147
148 /**
149 * Displays the newsletter access level.
150 *
151 * @param string $column_id The ID of the column to display.
152 * @param int $post_id The current post ID.
153 */
154 function render_newsletter_access_rows( $column_id, $post_id ) {
155 if ( NEWSLETTER_COLUMN_ID !== $column_id ) {
156 return;
157 }
158
159 $access_level = get_post_meta( $post_id, META_NAME_FOR_POST_LEVEL_ACCESS_SETTINGS, true );
160
161 switch ( $access_level ) {
162 case Token_Subscription_Service::POST_ACCESS_LEVEL_PAID_SUBSCRIBERS:
163 echo esc_html__( 'Paid Subscribers', 'jetpack' );
164 break;
165 case Token_Subscription_Service::POST_ACCESS_LEVEL_SUBSCRIBERS:
166 echo esc_html__( 'Subscribers', 'jetpack' );
167 break;
168 case Token_Subscription_Service::POST_ACCESS_LEVEL_EVERYBODY:
169 echo esc_html__( 'Everybody', 'jetpack' );
170 break;
171 default:
172 echo '';
173 }
174 }
175
176 /**
177 * Determine the amount of folks currently subscribed to the blog, splitted out in email_subscribers & social_followers & paid_subscribers
178 *
179 * @return array containing ['value' => ['email_subscribers' => 0, 'paid_subscribers' => 0, 'social_followers' => 0]]
180 */
181 function fetch_subscriber_counts() {
182 $subs_count = 0;
183 if ( is_wpcom() ) {
184 $subs_count = array(
185 'value' => \wpcom_fetch_subs_counts( true ),
186 );
187 } else {
188 $cache_key = 'wpcom_subscribers_totals';
189 $subs_count = get_transient( $cache_key );
190 if ( false === $subs_count || 'failed' === $subs_count['status'] ) {
191 $xml = new \Jetpack_IXR_Client();
192 $xml->query( 'jetpack.fetchSubscriberCounts' );
193
194 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.
195 $subs_count = array(
196 'status' => 'failed',
197 'code' => $xml->getErrorCode(),
198 'message' => $xml->getErrorMessage(),
199 'value' => ( isset( $subs_count['value'] ) ) ? $subs_count['value'] : array(
200 'email_subscribers' => 0,
201 'social_followers' => 0,
202 'paid_subscribers' => 0,
203 ),
204 );
205 } else {
206 $subs_count = array(
207 'status' => 'success',
208 'value' => $xml->getResponse(),
209 );
210 }
211 set_transient( $cache_key, $subs_count, 3600 ); // Try to cache the result for at least 1 hour.
212 }
213 }
214 return $subs_count;
215 }
216
217 /**
218 * Returns subscriber count based on include_social_followers attribute
219 *
220 * @param bool $include_social_followers Whether to include social followers in the count.
221 * @return int
222 */
223 function get_subscriber_count( $include_social_followers ) {
224 $counts = fetch_subscriber_counts();
225
226 if ( $include_social_followers ) {
227 $subscriber_count = $counts['value']['email_subscribers'] + $counts['value']['social_followers'];
228 } else {
229 $subscriber_count = $counts['value']['email_subscribers'];
230 }
231 return $subscriber_count;
232 }
233
234 /**
235 * Returns true if the block attributes contain a value for the given key.
236 *
237 * @param array $attributes Array containing the block attributes.
238 * @param string $key Block attribute key.
239 *
240 * @return boolean
241 */
242 function has_attribute( $attributes, $key ) {
243 return isset( $attributes[ $key ] ) && $attributes[ $key ] !== 'undefined';
244 }
245
246 /**
247 * Returns the value for the given attribute key, with the option of providing a default fallback value.
248 *
249 * @param array $attributes Array containing the block attributes.
250 * @param string $key Block attribute key.
251 * @param mixed $default Optional fallback value in case the key doesn't exist.
252 *
253 * @return mixed
254 */
255 function get_attribute( $attributes, $key, $default = null ) {
256 return has_attribute( $attributes, $key ) ? $attributes[ $key ] : $default;
257 }
258
259 /**
260 * Mimics getColorClassName, getFontSizeClass and getGradientClass from @wordpress/block-editor js package.
261 *
262 * @param string $setting Setting name.
263 * @param string $value Setting value.
264 *
265 * @return string
266 */
267 function get_setting_class_name( $setting, $value ) {
268 if ( ! $setting || ! $value ) {
269 return '';
270 }
271
272 return sprintf( 'has-%s-%s', $value, $setting );
273 }
274
275 /**
276 * Uses block attributes to generate an array containing the classes for various block elements.
277 * Based on Jetpack_Subscriptions_Widget::do_subscription_form() which the block was originally using.
278 *
279 * @param array $attributes Array containing the block attributes.
280 *
281 * @return array
282 */
283 function get_element_class_names_from_attributes( $attributes ) {
284 $text_color_class = get_setting_class_name( 'color', get_attribute( $attributes, 'textColor' ) );
285 $font_size_class = get_setting_class_name( 'font-size', get_attribute( $attributes, 'fontSize' ) );
286 $border_class = get_setting_class_name( 'border-color', get_attribute( $attributes, 'borderColor' ) );
287
288 $button_background_class = get_setting_class_name( 'background-color', get_attribute( $attributes, 'buttonBackgroundColor' ) );
289 $button_gradient_class = get_setting_class_name( 'gradient-background', get_attribute( $attributes, 'buttonGradient' ) );
290
291 $email_field_background_class = get_setting_class_name( 'background-color', get_attribute( $attributes, 'emailFieldBackgroundColor' ) );
292 $email_field_gradient_class = get_setting_class_name( 'gradient-background', get_attribute( $attributes, 'emailFieldGradient' ) );
293
294 $submit_button_classes = array_filter(
295 array(
296 'wp-block-button__link' => true,
297 'no-border-radius' => 0 === get_attribute( $attributes, 'borderRadius', 0 ),
298 $font_size_class => true,
299 $border_class => true,
300 'has-text-color' => ! empty( $text_color_class ),
301 $text_color_class => true,
302 'has-background' => ! empty( $button_background_class ) || ! empty( $button_gradient_class ),
303 $button_background_class => ! empty( $button_background_class ),
304 $button_gradient_class => ! empty( $button_gradient_class ),
305 )
306 );
307
308 $email_field_classes = array_filter(
309 array(
310 'no-border-radius' => 0 === get_attribute( $attributes, 'borderRadius', 0 ),
311 $font_size_class => true,
312 $border_class => true,
313 $email_field_background_class => true,
314 $email_field_gradient_class => true,
315 )
316 );
317
318 $block_wrapper_classes = array_filter(
319 array(
320 'wp-block-jetpack-subscriptions__supports-newline' => true,
321 'wp-block-jetpack-subscriptions__use-newline' => (bool) get_attribute( $attributes, 'buttonOnNewLine' ),
322 'wp-block-jetpack-subscriptions__show-subs' => (bool) get_attribute( $attributes, 'showSubscribersTotal' ),
323 )
324 );
325
326 return array(
327 'block_wrapper' => implode( ' ', array_keys( $block_wrapper_classes ) ),
328 'email_field' => implode( ' ', array_keys( $email_field_classes ) ),
329 'submit_button' => implode( ' ', array_keys( $submit_button_classes ) ),
330 );
331 }
332
333 /**
334 * Uses block attributes to generate an array containing the styles for various block elements.
335 * Based on Jetpack_Subscriptions_Widget::do_subscription_form() which the block was originally using.
336 *
337 * @param array $attributes Array containing the block attributes.
338 *
339 * @return array
340 */
341 function get_element_styles_from_attributes( $attributes ) {
342 $button_background_style = ! has_attribute( $attributes, 'buttonBackgroundColor' ) && has_attribute( $attributes, 'customButtonGradient' )
343 ? get_attribute( $attributes, 'customButtonGradient' )
344 : get_attribute( $attributes, 'customButtonBackgroundColor' );
345
346 $email_field_styles = '';
347 $submit_button_wrapper_styles = '';
348 $submit_button_styles = '';
349
350 if ( ! empty( $button_background_style ) ) {
351 $submit_button_styles .= sprintf( 'background: %s;', $button_background_style );
352 }
353
354 if ( has_attribute( $attributes, 'customTextColor' ) ) {
355 $submit_button_styles .= sprintf( 'color: %s;', get_attribute( $attributes, 'customTextColor' ) );
356 }
357
358 if ( has_attribute( $attributes, 'buttonWidth' ) ) {
359 $submit_button_wrapper_styles .= sprintf( 'width: %s;', get_attribute( $attributes, 'buttonWidth' ) );
360 $submit_button_wrapper_styles .= 'max-width: 100%;';
361
362 // Account for custom margins on inline forms.
363 $submit_button_styles .= true === get_attribute( $attributes, 'buttonOnNewLine' )
364 ? sprintf( 'width: calc(100%% - %dpx);', get_attribute( $attributes, 'spacing', DEFAULT_SPACING_VALUE ) )
365 : 'width: 100%;';
366 }
367
368 $font_size = get_attribute( $attributes, 'customFontSize', DEFAULT_FONTSIZE_VALUE );
369 $style = sprintf( 'font-size: %s%s;', $font_size, is_numeric( $font_size ) ? 'px' : '' );
370
371 $submit_button_styles .= $style;
372 $email_field_styles .= $style;
373
374 $padding = get_attribute( $attributes, 'padding', DEFAULT_PADDING_VALUE );
375 $style = sprintf( 'padding: %1$dpx %2$dpx %1$dpx %2$dpx;', $padding, round( $padding * 1.5 ) );
376
377 $submit_button_styles .= $style;
378 $email_field_styles .= $style;
379
380 $button_spacing = get_attribute( $attributes, 'spacing', DEFAULT_SPACING_VALUE );
381 if ( true === get_attribute( $attributes, 'buttonOnNewLine' ) ) {
382 $submit_button_styles .= sprintf( 'margin-top: %dpx;', $button_spacing );
383 } else {
384 $submit_button_styles .= 'margin: 0px; '; // Reset Safari's 2px default margin for buttons affecting input and button union
385 $submit_button_styles .= sprintf( 'margin-left: %dpx;', $button_spacing );
386 }
387
388 if ( has_attribute( $attributes, 'borderColor' ) ) {
389 $style = sprintf( 'border-color: %s;', get_attribute( $attributes, 'borderColor', '' ) );
390 $submit_button_styles .= $style;
391 $email_field_styles .= $style;
392 }
393
394 $style = sprintf( 'border-radius: %dpx;', get_attribute( $attributes, 'borderRadius', DEFAULT_BORDER_RADIUS_VALUE ) );
395 $submit_button_styles .= $style;
396 $email_field_styles .= $style;
397
398 $style = sprintf( 'border-width: %dpx;', get_attribute( $attributes, 'borderWeight', DEFAULT_BORDER_WEIGHT_VALUE ) );
399 $submit_button_styles .= $style;
400 $email_field_styles .= $style;
401
402 if ( has_attribute( $attributes, 'customBorderColor' ) ) {
403 $style = sprintf( 'border-color: %s; border-style: solid;', get_attribute( $attributes, 'customBorderColor' ) );
404
405 $submit_button_styles .= $style;
406 $email_field_styles .= $style;
407 }
408
409 return array(
410 'email_field' => $email_field_styles,
411 'submit_button' => $submit_button_styles,
412 'submit_button_wrapper' => $submit_button_wrapper_styles,
413 );
414 }
415
416 /**
417 * Subscriptions block render callback.
418 *
419 * @param array $attributes Array containing the block attributes.
420 *
421 * @return string
422 */
423 function render_block( $attributes ) {
424 // If the Subscriptions module is not active, don't render the block.
425 if ( ! Jetpack::is_module_active( 'subscriptions' ) ) {
426 return '';
427 }
428
429 if (
430 /** This filter is documented in class.jetpack-gutenberg.php */
431 apply_filters( 'jetpack_subscriptions_newsletter_feature_enabled', true )
432 && class_exists( '\Jetpack_Memberships' )
433 ) {
434 // We only want the sites that have newsletter feature enabled to be graced by this JavaScript and thickbox.
435 Jetpack_Gutenberg::load_assets_as_required( FEATURE_NAME, array( 'thickbox' ) );
436 if ( ! wp_style_is( 'enqueued' ) ) {
437 wp_enqueue_style( 'thickbox' );
438 }
439 } else {
440 Jetpack_Gutenberg::load_styles_as_required( FEATURE_NAME );
441 }
442
443 $subscribe_email = '';
444
445 /** This filter is documented in modules/contact-form/grunion-contact-form.php */
446 if ( is_wpcom() || false !== apply_filters( 'jetpack_auto_fill_logged_in_user', false ) ) {
447 $current_user = wp_get_current_user();
448 $subscribe_email = ! empty( $current_user->user_email ) ? $current_user->user_email : '';
449 }
450
451 // The block is using the Jetpack_Subscriptions_Widget backend, hence the need to increase the instance count.
452 ++Jetpack_Subscriptions_Widget::$instance_count;
453
454 $classes = get_element_class_names_from_attributes( $attributes );
455 $styles = get_element_styles_from_attributes( $attributes );
456 $include_social_followers = isset( $attributes['includeSocialFollowers'] ) ? (bool) get_attribute( $attributes, 'includeSocialFollowers' ) : true;
457
458 $data = array(
459 'widget_id' => Jetpack_Subscriptions_Widget::$instance_count,
460 'subscribe_email' => $subscribe_email,
461
462 'wrapper_attributes' => get_block_wrapper_attributes(
463 array(
464 'class' => $classes['block_wrapper'],
465 )
466 ),
467 'subscribe_placeholder' => get_attribute( $attributes, 'subscribePlaceholder', esc_html__( 'Type your email…', 'jetpack' ) ),
468 'submit_button_text' => get_attribute( $attributes, 'submitButtonText', esc_html__( 'Subscribe', 'jetpack' ) ),
469 'success_message' => get_attribute(
470 $attributes,
471 'successMessage',
472 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' )
473 ),
474 'show_subscribers_total' => (bool) get_attribute( $attributes, 'showSubscribersTotal' ),
475 'subscribers_total' => get_subscriber_count( $include_social_followers ),
476 'referer' => esc_url_raw(
477 ( is_ssl() ? 'https' : 'http' ) . '://' . ( isset( $_SERVER['HTTP_HOST'] ) ? wp_unslash( $_SERVER['HTTP_HOST'] ) : '' ) .
478 ( isset( $_SERVER['REQUEST_URI'] ) ? wp_unslash( $_SERVER['REQUEST_URI'] ) : '' )
479 ),
480 'source' => 'subscribe-block',
481 );
482
483 if ( is_wpcom() ) {
484 return render_wpcom_subscribe_form( $data, $classes, $styles );
485 }
486
487 return render_jetpack_subscribe_form( $data, $classes, $styles );
488 }
489
490 /**
491 * Get the post access level for the current post. Defaults to 'everybody' if the query is not for a single post
492 *
493 * @return string the actual post access level (see projects/plugins/jetpack/extensions/blocks/subscriptions/constants.js for the values).
494 */
495 function get_post_access_level_for_current_post() {
496 if ( ! is_singular() ) {
497 // There is no "actual" current post.
498 return Token_Subscription_Service::POST_ACCESS_LEVEL_EVERYBODY;
499 }
500
501 return Jetpack_Memberships::get_post_access_level();
502 }
503
504 /**
505 * Renders the WP.com version of the subscriptions block.
506 *
507 * @param array $data Array containing block view data.
508 * @param array $classes Array containing the classes for different block elements.
509 * @param array $styles Array containing the styles for different block elements.
510 *
511 * @return string
512 */
513 function render_wpcom_subscribe_form( $data, $classes, $styles ) {
514 global $current_blog;
515
516 $form_id = 'subscribe-blog' . ( Jetpack_Subscriptions_Widget::$instance_count > 1 ? '-' . Jetpack_Subscriptions_Widget::$instance_count : '' );
517 $url = defined( 'SUBSCRIBE_BLOG_URL' ) ? SUBSCRIBE_BLOG_URL : '';
518
519 ob_start();
520
521 Jetpack_Subscriptions_Widget::render_widget_status_messages(
522 array(
523 'success_message' => $data['success_message'],
524 )
525 );
526
527 $post_access_level = get_post_access_level_for_current_post();
528
529 ?>
530 <div <?php echo wp_kses_data( $data['wrapper_attributes'] ); ?>>
531 <div class="wp-block-jetpack-subscriptions__container">
532 <form
533 action="<?php echo esc_url( $url ); ?>"
534 method="post"
535 accept-charset="utf-8"
536 data-blog="<?php echo esc_attr( get_current_blog_id() ); ?>"
537 data-post_access_level="<?php echo esc_attr( $post_access_level ); ?>"
538 id="<?php echo esc_attr( $form_id ); ?>"
539 >
540 <?php
541 $email_field_id = 'subscribe-field';
542 $email_field_id .= Jetpack_Subscriptions_Widget::$instance_count > 1
543 ? '-' . Jetpack_Subscriptions_Widget::$instance_count
544 : '';
545 $label_field_id = $email_field_id . '-label';
546 ?>
547 <p id="subscribe-email">
548 <label
549 id="<?php echo esc_attr( $label_field_id ); ?>"
550 for="<?php echo esc_attr( $email_field_id ); ?>"
551 class="screen-reader-text"
552 >
553 <?php echo esc_html( $data['subscribe_placeholder'] ); ?>
554 </label>
555
556 <?php
557 printf(
558 '<input
559 required="required"
560 type="email"
561 name="email"
562 %1$s
563 style="%2$s"
564 placeholder="%3$s"
565 value="%4$s"
566 id="%5$s"
567 />',
568 ( ! empty( $classes['email_field'] )
569 ? 'class="' . esc_attr( $classes['email_field'] ) . '"'
570 : ''
571 ),
572 ( ! empty( $styles['email_field'] )
573 ? esc_attr( $styles['email_field'] )
574 : 'width: 95%; padding: 1px 10px'
575 ),
576 esc_attr( $data['subscribe_placeholder'] ),
577 esc_attr( $data['subscribe_email'] ),
578 esc_attr( $email_field_id )
579 );
580 ?>
581 </p>
582
583 <p id="subscribe-submit"
584 <?php if ( ! empty( $styles['submit_button_wrapper'] ) ) : ?>
585 style="<?php echo esc_attr( $styles['submit_button_wrapper'] ); ?>"
586 <?php endif; ?>
587 >
588 <input type="hidden" name="action" value="subscribe"/>
589 <input type="hidden" name="blog_id" value="<?php echo (int) $current_blog->blog_id; ?>"/>
590 <input type="hidden" name="source" value="<?php echo esc_url( $data['referer'] ); ?>"/>
591 <input type="hidden" name="sub-type" value="<?php echo esc_attr( $data['source'] ); ?>"/>
592 <input type="hidden" name="redirect_fragment" value="<?php echo esc_attr( $form_id ); ?>"/>
593 <?php wp_nonce_field( 'blogsub_subscribe_' . $current_blog->blog_id, '_wpnonce', false ); ?>
594 <button type="submit"
595 <?php if ( ! empty( $classes['submit_button'] ) ) : ?>
596 class="<?php echo esc_attr( $classes['submit_button'] ); ?>"
597 <?php endif; ?>
598 <?php if ( ! empty( $styles['submit_button'] ) ) : ?>
599 style="<?php echo esc_attr( $styles['submit_button'] ); ?>"
600 <?php endif; ?>
601 >
602 <?php
603 echo wp_kses(
604 html_entity_decode( $data['submit_button_text'], ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 ),
605 Jetpack_Subscriptions_Widget::$allowed_html_tags_for_submit_button
606 );
607 ?>
608 </button>
609 </p>
610 </form>
611 <?php if ( $data['show_subscribers_total'] && $data['subscribers_total'] ) : ?>
612 <div class="wp-block-jetpack-subscriptions__subscount">
613 <?php
614 /* translators: %s: number of folks following the blog */
615 echo esc_html( sprintf( _n( 'Join %s other follower', 'Join %s other followers', $data['subscribers_total'], 'jetpack' ), number_format_i18n( $data['subscribers_total'] ) ) );
616 ?>
617 </div>
618 <?php endif; ?>
619 </div>
620 </div>
621 <?php
622
623 return ob_get_clean();
624 }
625
626 /**
627 * Renders the Jetpack version of the subscriptions block.
628 *
629 * @param array $data Array containing block view data.
630 * @param array $classes Array containing the classes for different block elements.
631 * @param array $styles Array containing the styles for different block elements.
632 *
633 * @return string
634 */
635 function render_jetpack_subscribe_form( $data, $classes, $styles ) {
636 $form_id = sprintf( 'subscribe-blog-%s', $data['widget_id'] );
637 $subscribe_field_id = apply_filters( 'subscribe_field_id', 'subscribe-field', $data['widget_id'] );
638 ob_start();
639
640 Jetpack_Subscriptions_Widget::render_widget_status_messages(
641 array(
642 'success_message' => $data['success_message'],
643 )
644 );
645
646 $blog_id = \Jetpack_Options::get_option( 'id' );
647 $post_access_level = get_post_access_level_for_current_post();
648
649 ?>
650 <div <?php echo wp_kses_data( $data['wrapper_attributes'] ); ?>>
651 <div class="jetpack_subscription_widget">
652 <div class="wp-block-jetpack-subscriptions__container">
653 <form
654 action="#"
655 method="post"
656 accept-charset="utf-8"
657 data-blog="<?php echo esc_attr( $blog_id ); ?>"
658 data-post_access_level="<?php echo esc_attr( $post_access_level ); ?>"
659 id="<?php echo esc_attr( $form_id ); ?>"
660 >
661 <p id="subscribe-email">
662 <label id="jetpack-subscribe-label"
663 class="screen-reader-text"
664 for="<?php echo esc_attr( $subscribe_field_id . '-' . $data['widget_id'] ); ?>">
665 <?php echo esc_html( $data['subscribe_placeholder'] ); ?>
666 </label>
667 <input type="email" name="email" required="required"
668 <?php if ( ! empty( $classes['email_field'] ) ) : ?>
669 class="<?php echo esc_attr( $classes['email_field'] ); ?> required"
670 <?php endif; ?>
671 <?php if ( ! empty( $styles['email_field'] ) ) : ?>
672 style="<?php echo esc_attr( $styles['email_field'] ); ?>"
673 <?php endif; ?>
674 value="<?php echo esc_attr( $data['subscribe_email'] ); ?>"
675 id="<?php echo esc_attr( $subscribe_field_id . '-' . $data['widget_id'] ); ?>"
676 placeholder="<?php echo esc_attr( $data['subscribe_placeholder'] ); ?>"
677 />
678 </p>
679
680 <p id="subscribe-submit"
681 <?php if ( ! empty( $styles['submit_button_wrapper'] ) ) : ?>
682 style="<?php echo esc_attr( $styles['submit_button_wrapper'] ); ?>"
683 <?php endif; ?>
684 >
685 <input type="hidden" name="action" value="subscribe"/>
686 <input type="hidden" name="blog_id" value="<?php echo (int) $blog_id; ?>"/>
687 <input type="hidden" name="source" value="<?php echo esc_url( $data['referer'] ); ?>"/>
688 <input type="hidden" name="sub-type" value="<?php echo esc_attr( $data['source'] ); ?>"/>
689 <input type="hidden" name="redirect_fragment" value="<?php echo esc_attr( $form_id ); ?>"/>
690 <?php
691 if ( is_user_logged_in() ) {
692 wp_nonce_field( 'blogsub_subscribe_' . get_current_blog_id(), '_wpnonce', false );
693 }
694 ?>
695 <button type="submit"
696 <?php if ( ! empty( $classes['submit_button'] ) ) : ?>
697 class="<?php echo esc_attr( $classes['submit_button'] ); ?>"
698 <?php endif; ?>
699 <?php if ( ! empty( $styles['submit_button'] ) ) : ?>
700 style="<?php echo esc_attr( $styles['submit_button'] ); ?>"
701 <?php endif; ?>
702 name="jetpack_subscriptions_widget"
703 >
704 <?php
705 echo wp_kses(
706 html_entity_decode( $data['submit_button_text'], ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 ),
707 Jetpack_Subscriptions_Widget::$allowed_html_tags_for_submit_button
708 );
709 ?>
710 </button>
711 </p>
712 </form>
713
714 <?php if ( $data['show_subscribers_total'] && $data['subscribers_total'] ) : ?>
715 <div class="wp-block-jetpack-subscriptions__subscount">
716 <?php
717 /* translators: %s: number of folks following the blog */
718 echo esc_html( sprintf( _n( 'Join %s other subscriber', 'Join %s other subscribers', $data['subscribers_total'], 'jetpack' ), number_format_i18n( $data['subscribers_total'] ) ) );
719 ?>
720 </div>
721 <?php endif; ?>
722 </div>
723 </div>
724 </div>
725 <?php
726
727 return ob_get_clean();
728 }
729
730 /**
731 * Filter excerpts looking for subscription data.
732 *
733 * @param string $excerpt The extrapolated excerpt string.
734 * @param \WP_Post $post The current post being processed (in `get_the_excerpt`).
735 *
736 * @return mixed
737 */
738 function jetpack_filter_excerpt_for_newsletter( $excerpt, $post = null ) {
739 // The blogmagazine theme is overriding WP core `get_the_excerpt` filter and only passing the excerpt
740 // TODO: Until this is fixed, return the excerpt without gating. See https://github.com/Automattic/jetpack/pull/28102#issuecomment-1369161116
741 if ( $post && false !== strpos( $post->post_content, '<!-- wp:jetpack/subscriptions -->' ) ) {
742 $excerpt .= sprintf(
743 // translators: %s is the permalink url to the current post.
744 __( "<p><a href='%s'>View post</a> to subscribe to site newsletter.</p>", 'jetpack' ),
745 get_post_permalink()
746 );
747 }
748 return $excerpt;
749 }
750
751 /**
752 * Gate access to posts
753 *
754 * @param string $the_content Post content.
755 *
756 * @return string
757 */
758 function maybe_get_locked_content( $the_content ) {
759 require_once JETPACK__PLUGIN_DIR . 'modules/memberships/class-jetpack-memberships.php';
760
761 if ( Jetpack_Memberships::user_can_view_post() ) {
762 return $the_content;
763 }
764
765 $post_access_level = Jetpack_Memberships::get_post_access_level();
766 return get_locked_content_placeholder_text( $post_access_level );
767 }
768
769 /**
770 * Gate access to comments. We want to close comments on private sites.
771 *
772 * @param bool $default_comments_open Default state of the comments_open filter.
773 * @param int $post_id Current post id.
774 *
775 * @return bool
776 */
777 function maybe_close_comments( $default_comments_open, $post_id ) {
778 if ( ! $default_comments_open || ! $post_id ) {
779 return $default_comments_open;
780 }
781
782 require_once JETPACK__PLUGIN_DIR . 'modules/memberships/class-jetpack-memberships.php';
783 return Jetpack_Memberships::user_can_view_post();
784 }
785
786 /**
787 * Gate access to exisiting comments
788 *
789 * @param string $comment The comment.
790 *
791 * @return string
792 */
793 function maybe_gate_existing_comments( $comment ) {
794 if ( empty( $comment ) ) {
795 return $comment;
796 }
797
798 require_once JETPACK__PLUGIN_DIR . 'modules/memberships/class-jetpack-memberships.php';
799 if ( Jetpack_Memberships::user_can_view_post() ) {
800 return $comment;
801 }
802 return '';
803 }
804
805 /**
806 * Placeholder text for non-subscribers
807 *
808 * @param string $newsletter_access_level The newsletter access level.
809 * @return string
810 */
811 function get_locked_content_placeholder_text( $newsletter_access_level ) {
812 // Default to subscribers
813 $access_level = __( 'subscribers', 'jetpack' );
814
815 // Only display this text when Stripe is connected and the post is marked for paid subscribers
816 if (
817 $newsletter_access_level === 'paid_subscribers'
818 && ! empty( Jetpack_Memberships::get_connected_account_id() )
819 ) {
820 $access_level = __( 'paid subscribers', 'jetpack' );
821 }
822
823 return do_blocks(
824 '<!-- wp:group {"style":{"spacing":{"padding":{"top":"var:preset|spacing|80","right":"var:preset|spacing|80","bottom":"var:preset|spacing|80","left":"var:preset|spacing|80"}},"border":{"width":"1px","radius":"4px"}},"borderColor":"primary","layout":{"type":"constrained","contentSize":"400px"}} -->
825 <div class="wp-block-group has-border-color has-primary-border-color" style="border-width:1px;border-radius:4px;padding-top:var(--wp--preset--spacing--80);padding-right:var(--wp--preset--spacing--80);padding-bottom:var(--wp--preset--spacing--80);padding-left:var(--wp--preset--spacing--80)"><!-- wp:heading {"textAlign":"center","style":{"typography":{"fontSize":"24px"},"spacing":{"margin":{"bottom":"var:preset|spacing|60"}}}} -->
826 <h2 class="wp-block-heading has-text-align-center" style="margin-bottom:var(--wp--preset--spacing--60);font-size:24px">' .
827
828 /* translators: Newsletter access. Possible values are "paid newsletters" and "subscribers" */
829 sprintf( esc_html__( 'This post is for %s', 'jetpack' ), $access_level )
830
831 . '</h2>
832 <!-- /wp:heading -->
833
834 <!-- wp:jetpack/subscriptions {"borderRadius":50,"borderColor":"primary","className":"is-style-compact"} /-->
835 </div>
836 <!-- /wp:group -->'
837 );
838 }
839