PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 12.3
Jetpack – WP Security, Backup, Speed, & Growth v12.3
16.2-beta 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 All 501 releases
jetpack / modules / sharedaddy / sharedaddy.php

sharedaddy.php in Jetpack – WP Security, Backup, Speed, & Growth 12.3, at modules/sharedaddy/sharedaddy.php

463 lines 13.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Jetpack's Sharing feature, nee Sharedaddy.
4 * The most super duper sharing tool on the interwebs.
5 *
6 * @package automattic/jetpack
7 */
8
9 // Set up Sharing in wp-admin.
10 require_once plugin_dir_path( __FILE__ ) . 'sharing.php';
11
12 /**
13 * Send an email via the Email sharing button.
14 *
15 * @param array $data Array of information about the shared message.
16 *
17 * @return void
18 *
19 * @deprecated 11.0
20 */
21 function sharing_email_send_post( $data ) {
22
23 $content = sharing_email_send_post_content( $data );
24 // Borrowed from wp_mail();
25
26 if ( empty( $_SERVER['SERVER_NAME'] ) ) {
27 return;
28 }
29
30 $sitename = strtolower( sanitize_text_field( wp_unslash( $_SERVER['SERVER_NAME'] ) ) );
31 if ( substr( $sitename, 0, 4 ) === 'www.' ) {
32 $sitename = substr( $sitename, 4 );
33 }
34
35 /** This filter is documented in core/src/wp-includes/pluggable.php */
36 $from_email = apply_filters( 'wp_mail_from', 'wordpress@' . $sitename );
37
38 if ( ! empty( $data['name'] ) ) {
39 $s_name = (string) $data['name'];
40 $name_needs_encoding_regex =
41 '/[' .
42 // SpamAssasin's list of characters which "need MIME" encoding
43 '\x00-\x08\x0b\x0c\x0e-\x1f\x7f-\xff' .
44 // Our list of "unsafe" characters
45 '<\r\n' .
46 ']/';
47
48 $needs_encoding =
49 // If it contains any blocked chars.
50 preg_match( $name_needs_encoding_regex, $s_name ) ||
51 // Or if we can't use `mb_convert_encoding`
52 ! function_exists( 'mb_convert_encoding' ) ||
53 // Or if it's not already ASCII
54 mb_convert_encoding( $data['name'], 'ASCII' ) !== $s_name;
55
56 if ( $needs_encoding ) {
57 $data['name'] = sprintf( '=?UTF-8?B?%s?=', base64_encode( $data['name'] ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
58 }
59 }
60
61 $headers = array();
62 $headers[] = sprintf( 'From: %1$s <%2$s>', $data['name'], $from_email );
63 $headers[] = sprintf( 'Reply-To: %1$s <%2$s>', $data['name'], $data['source'] );
64
65 // Make sure to pass the title through the normal sharing filters.
66 $title = $data['sharing_source']->get_share_title( $data['post']->ID );
67
68 /**
69 * Filter the Sharing Email Send Post Subject.
70 *
71 * @module sharedaddy
72 *
73 * @since 5.8.0
74 *
75 * @param string $var Sharing Email Send Post Subject. Default is "Shared Post".
76 */
77 $subject = apply_filters( 'wp_sharing_email_send_post_subject', '[' . __( 'Shared Post', 'jetpack' ) . '] ' . $title );
78
79 wp_mail( $data['target'], $subject, $content, $headers );
80 }
81
82 /**
83 * Checks for spam using Akismet if available.
84 * Return $data as it if email about to be send out is not spam.
85 *
86 * @param array $data Array of information about the shared message.
87 *
88 * @return array $data
89 *
90 * @deprecated 11.0
91 */
92 function sharing_email_check_for_spam_via_akismet( $data ) {
93
94 if ( ! Jetpack::is_akismet_active() ) {
95 return $data;
96 }
97
98 // Prepare the body_request for akismet
99 $body_request = array(
100 'blog' => get_option( 'home' ),
101 'permalink' => $data['sharing_source']->get_share_url( $data['post']->ID ),
102 'comment_type' => 'share',
103 'comment_author' => $data['name'],
104 'comment_author_email' => $data['source'],
105 'comment_content' => sharing_email_send_post_content( $data ),
106 'user_agent' => ( isset( $_SERVER['HTTP_USER_AGENT'] )
107 ? filter_var( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) )
108 : null
109 ),
110 );
111
112 if ( method_exists( 'Akismet', 'http_post' ) ) {
113 $body_request['user_ip'] = Akismet::get_ip_address();
114 $response = Akismet::http_post( build_query( $body_request ), 'comment-check' );
115 } else {
116 global $akismet_api_host, $akismet_api_port;
117 $body_request['user_ip'] = ( isset( $_SERVER['REMOTE_ADDR'] )
118 ? filter_var( wp_unslash( $_SERVER['REMOTE_ADDR'] ) )
119 : null
120 );
121 $response = akismet_http_post( build_query( $body_request ), $akismet_api_host, '/1.1/comment-check', $akismet_api_port );
122 }
123
124 /*
125 * The Response is spam lets not send the email.
126 * 'true' is spam
127 */
128 if (
129 ! empty( $response )
130 && isset( $response[1] )
131 && 'true' == trim( $response[1] ) // phpcs:ignore Universal.Operators.StrictComparisons.LooseEqual -- response comes from the Akismet API.
132 ) {
133 return false; // don't send the email
134 }
135 return $data;
136 }
137
138 /**
139 * Content of the emails sent to the target email address.
140 *
141 * @param array $data Array of information about the shared message.
142 *
143 * @return string $content
144 *
145 * @deprecated 11.0
146 */
147 function sharing_email_send_post_content( $data ) {
148 $content = sprintf(
149 /* translators: included in email when post is shared via email. First item is sender's name. Second is sender's email address. */
150 __( '%1$s (%2$s) thinks you may be interested in the following post:', 'jetpack' ),
151 $data['name'],
152 $data['source']
153 );
154 $content .= "\n\n";
155 // Make sure to pass the title and URL through the normal sharing filters.
156 $content .= $data['sharing_source']->get_share_title( $data['post']->ID ) . "\n";
157 $content .= $data['sharing_source']->get_share_url( $data['post']->ID ) . "\n";
158 return $content;
159 }
160
161 /**
162 * Add a meta box to the post editing screen for sharing.
163 *
164 * @return void
165 */
166 function sharing_add_meta_box() {
167 global $post;
168 if ( empty( $post ) ) { // If a current post is not defined, such as when editing a comment.
169 return;
170 }
171
172 /**
173 * Filter whether to display the Sharing Meta Box or not.
174 *
175 * @module sharedaddy
176 *
177 * @since 3.8.0
178 *
179 * @param bool true Display Sharing Meta Box.
180 * @param $post Post.
181 */
182 if ( ! apply_filters( 'sharing_meta_box_show', true, $post ) ) {
183 return;
184 }
185
186 $post_types = get_post_types( array( 'public' => true ) );
187 /**
188 * Filter the Sharing Meta Box title.
189 *
190 * @module sharedaddy
191 *
192 * @since 2.2.0
193 *
194 * @param string $var Sharing Meta Box title. Default is "Sharing".
195 */
196 $title = apply_filters( 'sharing_meta_box_title', __( 'Sharing', 'jetpack' ) );
197 if ( $post->ID !== get_option( 'page_for_posts' ) ) {
198 foreach ( $post_types as $post_type ) {
199 add_meta_box( 'sharing_meta', $title, 'sharing_meta_box_content', $post_type, 'side', 'default', array( '__back_compat_meta_box' => true ) );
200 }
201 }
202 }
203
204 /**
205 * Content of the meta box.
206 *
207 * @param WP_Post $post The post to share.
208 *
209 * @return void
210 */
211 function sharing_meta_box_content( $post ) {
212 /**
213 * Fires before the sharing meta box content.
214 *
215 * @module sharedaddy
216 *
217 * @since 2.2.0
218 *
219 * @param WP_Post $post The post to share.
220 */
221 do_action( 'start_sharing_meta_box_content', $post );
222
223 $disabled = get_post_meta( $post->ID, 'sharing_disabled', true ); ?>
224
225 <p>
226 <label for="enable_post_sharing">
227 <input type="checkbox" name="enable_post_sharing" id="enable_post_sharing" value="1" <?php checked( ! $disabled ); ?>>
228 <?php esc_html_e( 'Show sharing buttons.', 'jetpack' ); ?>
229 </label>
230 <input type="hidden" name="sharing_status_hidden" value="1" />
231 </p>
232
233 <?php
234 /**
235 * Fires after the sharing meta box content.
236 *
237 * @module sharedaddy
238 *
239 * @since 2.2.0
240 *
241 * @param WP_Post $post The post to share.
242 */
243 do_action( 'end_sharing_meta_box_content', $post );
244 }
245
246 /**
247 * Save new sharing status in post meta in the meta box.
248 *
249 * @param int $post_id Post ID.
250 *
251 * @return int
252 */
253 function sharing_meta_box_save( $post_id ) {
254 if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
255 return $post_id;
256 }
257
258 if ( ! isset( $_POST['post_type'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Core takes care of the validation.
259 return $post_id;
260 }
261
262 $post_type_object = get_post_type_object( sanitize_key( $_POST['post_type'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Core takes care of the validation.
263
264 // Record sharing disable.
265 if (
266 $post_type_object->public
267 && current_user_can( 'edit_post', $post_id )
268 && isset( $_POST['sharing_status_hidden'] ) // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Core takes care of the validation.
269 ) {
270 if ( ! isset( $_POST['enable_post_sharing'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Core takes care of the validation.
271 update_post_meta( $post_id, 'sharing_disabled', 1 );
272 } else {
273 delete_post_meta( $post_id, 'sharing_disabled' );
274 }
275 }
276
277 return $post_id;
278 }
279
280 /**
281 * If Sharing is disabled, disable the meta box.
282 *
283 * @param bool $protected Whether the key is considered protected.
284 * @param string $meta_key Metadata key.
285 *
286 * @return bool
287 */
288 function sharing_meta_box_protected( $protected, $meta_key ) {
289 if ( 'sharing_disabled' === $meta_key ) {
290 $protected = true;
291 }
292
293 return $protected;
294 }
295 add_filter( 'is_protected_meta', 'sharing_meta_box_protected', 10, 2 );
296
297 /**
298 * Add link to sharing settings in the Plugins screen.
299 *
300 * @param array $links An array of plugin action links.
301 *
302 * @return array
303 */
304 function sharing_plugin_settings( $links ) {
305 $settings_link = '<a href="options-general.php?page=sharing.php">' . __( 'Settings', 'jetpack' ) . '</a>';
306 array_unshift( $links, $settings_link );
307 return $links;
308 }
309
310 /**
311 * Add links to settings and support in the plugin row.
312 *
313 * @param array $links An array of the plugin's metadata, including the version, author, author URI, and plugin URI.
314 * @param string $file Path to the plugin file relative to the plugins directory.
315 *
316 * @return array
317 */
318 function sharing_add_plugin_settings( $links, $file ) {
319 if ( $file === basename( __DIR__ ) . '/' . basename( __FILE__ ) ) {
320 $links[] = '<a href="options-general.php?page=sharing.php">' . __( 'Settings', 'jetpack' ) . '</a>';
321 $links[] = '<a href="https://support.wordpress.com/sharing/" rel="noopener noreferrer" target="_blank">' . __( 'Support', 'jetpack' ) . '</a>';
322 }
323
324 return $links;
325 }
326
327 /**
328 * Disable sharing on the frontend if disabled in the admin.
329 *
330 * @return void
331 */
332 function sharing_init() {
333 if ( Jetpack_Options::get_option_and_ensure_autoload( 'sharedaddy_disable_resources', '0' ) ) {
334 add_filter( 'sharing_js', '__return_false' );
335 remove_action( 'wp_head', 'sharing_add_header', 1 );
336 }
337 }
338
339 /**
340 * Add settings to disable CSS and JS normally enqueued by our feature.
341 *
342 * @return void
343 */
344 function sharing_global_resources() {
345 $disable = get_option( 'sharedaddy_disable_resources' );
346 ?>
347 <tr valign="top">
348 <th scope="row"><label for="disable_css"><?php esc_html_e( 'Disable CSS and JS', 'jetpack' ); ?></label></th>
349 <td>
350 <?php
351 printf(
352 '<input id="disable_css" type="checkbox" name="disable_resources"%1$s /> <small><em>%2$s</em></small>',
353 ( 1 == $disable ) ? ' checked="checked"' : '', // phpcs:ignore Universal.Operators.StrictComparisons.LooseEqual
354 esc_html__( 'Advanced. If this option is checked, you must include these files in your theme manually for the sharing links to work.', 'jetpack' )
355 );
356 ?>
357 </td>
358 </tr>
359 <?php
360 }
361
362 /**
363 * Save settings to disable CSS and JS normally enqueued by our feature.
364 *
365 * @return void
366 */
367 function sharing_global_resources_save() {
368 update_option( 'sharedaddy_disable_resources', isset( $_POST['disable_resources'] ) ? 1 : 0 ); // phpcs:ignore WordPress.Security.NonceVerification.Missing -- nonce handling is handled for all elements at once.
369 }
370
371 /**
372 * Returns the Recaptcha site/public key.
373 *
374 * Supports legacy RECAPTCHA_PUBLIC_KEY or RECAPTCHA_SITE_KEY.
375 *
376 * @return string
377 *
378 * @deprecated 11.0
379 */
380 function sharing_recaptcha_site_key() {
381 if ( ! defined( 'RECAPTCHA_PUBLIC_KEY' ) && ! defined( 'RECAPTCHA_SITE_KEY' ) ) {
382 return '';
383 }
384
385 if ( defined( 'RECAPTCHA_PUBLIC_KEY' ) && ! defined( 'RECAPTCHA_SITE_KEY' ) ) {
386 define( 'RECAPTCHA_SITE_KEY', RECAPTCHA_PUBLIC_KEY );
387 }
388
389 return RECAPTCHA_SITE_KEY;
390 }
391
392 /**
393 * Returns the Recaptcha private/secret key.
394 *
395 * Supports legacy RECAPTCHA_PRIVATE_KEY or RECAPTCHA_SECRET_KEY.
396 *
397 * @return string
398 *
399 * @deprecated 11.0
400 */
401 function sharing_recaptcha_secret_key() {
402 if ( ! defined( 'RECAPTCHA_PRIVATE_KEY' ) && ! defined( 'RECAPTCHA_SECRET_KEY' ) ) {
403 return '';
404 }
405
406 if ( defined( 'RECAPTCHA_PRIVATE_KEY' ) && ! defined( 'RECAPTCHA_SECRET_KEY' ) ) {
407 define( 'RECAPTCHA_SECRET_KEY', RECAPTCHA_PRIVATE_KEY );
408 }
409
410 return RECAPTCHA_SECRET_KEY;
411 }
412
413 /**
414 * Contents of a reCAPTCHA box.
415 *
416 * @return void
417 *
418 * @deprecated 11.0
419 */
420 function sharing_email_dialog() {
421 require_once plugin_dir_path( __FILE__ ) . 'recaptcha.php';
422
423 $recaptcha = new Jetpack_ReCaptcha(
424 sharing_recaptcha_site_key(),
425 sharing_recaptcha_secret_key(),
426 array( 'script_lazy' => true )
427 );
428 echo $recaptcha->get_recaptcha_html(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escaped in method.
429 }
430
431 /**
432 * Short-circuit the email sharing button based on the results of reCAPTCHA.
433 *
434 * @param bool $true Should we check if the message isn't spam.
435 * @param object $post Post information.
436 * @param array $data Information about the shared message.
437 *
438 * @deprecated 11.0
439 */
440 function sharing_email_check( $true, $post, $data ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
441 require_once plugin_dir_path( __FILE__ ) . 'recaptcha.php';
442
443 $recaptcha = new Jetpack_ReCaptcha( sharing_recaptcha_site_key(), sharing_recaptcha_secret_key(), array( 'script_lazy' => true ) );
444 $response = ! empty( $_POST['g-recaptcha-response'] ) // phpcs:ignore WordPress.Security.NonceVerification.Missing -- we do not change anything on the site based on that.
445 ? filter_var( wp_unslash( $_POST['g-recaptcha-response'] ) ) // phpcs:ignore WordPress.Security.NonceVerification.Missing -- we do not change anything on the site based on that.
446 : '';
447 $remote_addr = ! empty( $_SERVER['REMOTE_ADDR'] )
448 ? filter_var( wp_unslash( $_SERVER['REMOTE_ADDR'] ) )
449 : '';
450 $result = $recaptcha->verify( $response, $remote_addr );
451
452 return ( true === $result );
453 }
454
455 add_action( 'init', 'sharing_init' );
456 add_action( 'add_meta_boxes', 'sharing_add_meta_box' );
457 add_action( 'save_post', 'sharing_meta_box_save' );
458 add_action( 'edit_attachment', 'sharing_meta_box_save' );
459 add_action( 'sharing_global_options', 'sharing_global_resources', 30 );
460 add_action( 'sharing_admin_update', 'sharing_global_resources_save' );
461 add_action( 'plugin_action_links_' . basename( __DIR__ ) . '/' . basename( __FILE__ ), 'sharing_plugin_settings', 10, 4 );
462 add_filter( 'plugin_row_meta', 'sharing_add_plugin_settings', 10, 2 );
463