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