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