PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.3-a.7
Jetpack – WP Security, Backup, Speed, & Growth v16.3-a.7
16.3-a.5 16.3-a.7 16.3-a.3 16.3-a.1 16.2 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 All 506 releases
← All changes | extensions/blocks/sharing-button/sharing-button.php +261 -28 13.0.2 → 16.3-a.7 View file →
@@ -1,9 +1,9 @@
1 1 <?php
2 2 /**
3 3 * Sharing Buttons Block.
4 4 *
5 - * @since 11.x
5 + * @since 13.1
6 6 *
7 7 * @package automattic/jetpack
8 8 */
9 9
@@ -9,13 +9,23 @@
9 9
10 10 namespace Automattic\Jetpack\Extensions\Sharing_Button_Block;
11 11
12 12 use Automattic\Jetpack\Blocks;
13 +use Automattic\Jetpack\Modules;
14 +use Automattic\Jetpack\Status\Host;
13 15 use Jetpack_Gutenberg;
16 +use WP_Block_Template;
14 17
18 +if ( ! defined( 'ABSPATH' ) ) {
19 + exit( 0 );
20 +}
21 +
15 22 require_once __DIR__ . '/class-sharing-source-block.php';
16 23 require_once __DIR__ . '/components/social-icons.php';
17 24
25 +const PARENT_BLOCK_NAME = 'jetpack/sharing-buttons';
26 +const INNER_BLOCK_NAME = 'jetpack/sharing-button';
27 +
18 28 /**
19 29 * Registers the block for use in Gutenberg
20 30 * This is done via an action so that we can disable
21 31 * registration if we need to.
@@ -24,8 +34,14 @@
24 34 Blocks::jetpack_register_block(
25 35 __DIR__,
26 36 array( 'render_callback' => __NAMESPACE__ . '\render_block' )
27 37 );
38 +
39 + /*
40 + * Automatically add the sharing block to the end of single posts.
41 + */
42 + add_filter( 'hooked_block_types', __NAMESPACE__ . '\add_block_to_single_posts_template', 10, 4 );
43 + add_filter( 'hooked_block_' . PARENT_BLOCK_NAME, __NAMESPACE__ . '\add_default_services_to_block', 10, 5 );
28 44 }
29 45 add_action( 'init', __NAMESPACE__ . '\register_block' );
30 46
31 47 /**
@@ -32,44 +48,108 @@
32 48 * Sharing Buttons block registration/dependency declaration.
33 49 *
34 50 * @param array $attr Array containing the Sharing Buttons block attributes.
35 51 * @param string $content String containing the Sharing Buttons block content.
36 - * @param array $block Array containing block data.
52 + * @param object $block Object containing block data.
37 53 *
38 54 * @return string
39 55 */
40 56 function render_block( $attr, $content, $block ) {
41 - global $post;
42 - $post_id = $block->context['postId'];
43 - $title = $attr['label'] ?? $attr['service'];
57 + $services = get_services();
58 + if ( ! isset( $attr['service'] ) || ! array_key_exists( $attr['service'], $services ) ) {
59 + return $content;
60 + }
44 61
45 - $style_type = $block->context['styleType'];
46 - $style = 'style-' . $style_type;
47 - $query = 'share=' . $attr['service'] . '&nb=1';
62 + $service_name = $attr['service'];
63 + $title = $attr['label'] ?? $service_name;
64 + $icon = get_social_logo( $service_name );
65 + $style_type = $block->context['styleType'] ?? 'icon-text';
66 + $post_id = $block->context['postId'] ?? 0;
67 + $data_shared = sprintf(
68 + 'sharing-%1$s-%2$d',
69 + $service_name,
70 + $post_id
71 + );
48 72
49 - $data_shared = 'sharing-' . $attr['service'] . '-' . $post_id;
73 + $service = new $services[ $service_name ]( $service_name, array() );
74 + $link_props = $service->get_link(
75 + $post_id,
76 + 'share=' . esc_attr( $service_name ) . '&nb=1',
77 + esc_attr( $data_shared )
78 + );
79 + $link_url = $link_props['url'];
80 + $link_classes = sprintf(
81 + 'jetpack-sharing-button__button style-%1$s share-%2$s',
82 + $style_type,
83 + $service_name
84 + );
50 85
51 - $services = get_services();
52 - $service = new $services[ $attr['service'] ]( $attr['service'], array() );
53 - $link_props = $service->get_link( $post, $query, $data_shared );
86 + $accessible_name = sprintf(
87 + /* translators: %s refers to a string representation of sharing service, e.g. Facebook */
88 + esc_html__( 'Share on %s', 'jetpack' ),
89 + esc_html( $title )
90 + );
54 91
55 - $link_url = $link_props['url'];
56 - $icon = get_social_logo( $attr['service'] );
57 - $sharing_link_class = 'jetpack-sharing-button__button ' . $style . ' share-' . $attr['service'];
92 + $accessible_name .= __( ' (Opens in new window)', 'jetpack' );
58 93
59 - $link_aria_label = sprintf(
60 - /* translators: %s refers to a string representation of sharing service, e.g. Facebook */
61 - esc_html__( 'Share on %s', 'jetpack' ),
62 - esc_html( $title )
94 + $block_class_name = 'jetpack-sharing-button__list-item';
95 +
96 + if ( $service_name === 'share' ) {
97 + $block_class_name .= ' tooltip';
98 + /* translators: aria label for SMS sharing button */
99 + $accessible_name = esc_attr__( 'Share using Native tools', 'jetpack' );
100 + $link_props = $service->get_link( $post_id );
101 + }
102 +
103 + $link_url = $link_props['url'];
104 + $link_classes = sprintf(
105 + 'jetpack-sharing-button__button style-%1$s share-%2$s',
106 + $style_type,
107 + $service_name
63 108 );
64 109
110 + $styles = array();
111 + if (
112 + array_key_exists( 'iconColorValue', $block->context )
113 + && ! empty( $block->context['iconColorValue'] )
114 + ) {
115 + $styles['color'] = $block->context['iconColorValue'];
116 + }
117 + if (
118 + array_key_exists( 'iconBackgroundColorValue', $block->context )
119 + && ! empty( $block->context['iconBackgroundColorValue'] )
120 + ) {
121 + $styles['background-color'] = $block->context['iconBackgroundColorValue'];
122 + }
123 + $link_styles = '';
124 + foreach ( $styles as $property => $value ) {
125 + $link_styles .= $property . ':' . $value . ';';
126 + }
127 +
65 128 Jetpack_Gutenberg::load_assets_as_required( __DIR__ );
66 129
67 - $component = '<li class="jetpack-sharing-button__list-item">';
68 - $component .= '<a rel="nofollow noopener noreferrer" class="' . esc_attr( $sharing_link_class ) . '" href="' . esc_attr( $link_url ) . '" target="_blank" ';
69 - $component .= 'data-service="' . esc_attr( $attr['service'] ) . '" data-shared="' . esc_attr( $data_shared ) . '" aria-label="' . esc_attr( $link_aria_label ) . '" primary>';
70 - $component .= $icon;
130 + $component = '<li class="' . esc_attr( $block_class_name ) . '">';
131 + $component .= sprintf(
132 + '<a href="%1$s" target="_blank" rel="nofollow noopener noreferrer" class="%2$s" style="%3$s" data-service="%4$s" data-shared="%5$s" aria-labelledby="%5$s">',
133 + esc_url( $link_url ),
134 + esc_attr( $link_classes ),
135 + esc_attr( $link_styles ),
136 + esc_attr( $service_name ),
137 + esc_attr( $data_shared )
138 + );
139 +
140 + // Add hidden span with accessible name
141 + $component .= sprintf(
142 + '<span id="%s" hidden>%s</span>',
143 + esc_attr( $data_shared ),
144 + esc_html( $accessible_name )
145 + );
146 +
147 + $component .= $style_type !== 'text' ? $icon : '';
71 148 $component .= '<span class="jetpack-sharing-button__service-label" aria-hidden="true">' . esc_html( $title ) . '</span>';
149 + if ( $service_name === 'share' ) {
150 + $component .= '<span class="tooltiptext" aria-live="assertive">' . esc_html__( 'Copied to clipboard', 'jetpack' ) . '</span>';
151 + }
72 152 $component .= '</a>';
73 153 $component .= '</li>';
74 154
75 155 return $component;
@@ -89,14 +169,16 @@
89 169 'reddit' => Share_Reddit_Block::class,
90 170 'twitter' => Share_Twitter_Block::class,
91 171 'tumblr' => Share_Tumblr_Block::class,
92 172 'pinterest' => Share_Pinterest_Block::class,
93 - 'pocket' => Share_Pocket_Block::class,
94 173 'telegram' => Share_Telegram_Block::class,
174 + 'threads' => Share_Threads_Block::class,
95 175 'whatsapp' => Jetpack_Share_WhatsApp_Block::class,
96 176 'mastodon' => Share_Mastodon_Block::class,
97 177 'nextdoor' => Share_Nextdoor_Block::class,
178 + 'bluesky' => Share_Bluesky_Block::class,
98 179 'x' => Share_X_Block::class,
180 + 'share' => Share_Native_Block::class,
99 181 );
100 182
101 183 return $services;
102 184 }
@@ -112,12 +194,163 @@
112 194 // Only process if: single post and share={service} defined
113 195 if ( ( is_page() || is_single() ) && isset( $_GET['share'] ) && is_string( $_GET['share'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
114 196 $services = get_services();
115 197 $service_name = sanitize_text_field( wp_unslash( $_GET['share'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
116 - $service = new $services[ ( $service_name ) ]( $service_name, array() ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
117 - if ( $service ) {
118 - $service->process_request( $post, $_POST ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
198 +
199 + // Only allow services that have been defined in get_services().
200 + if ( ! array_key_exists( $service_name, $services ) ) {
201 + return;
119 202 }
203 +
204 + $service = new $services[ ( $service_name ) ]( $service_name, array() );
205 + $service->process_request( $post, $_POST ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
120 206 }
121 207 }
122 208
123 -add_action( 'template_redirect', __NAMESPACE__ . '\sharing_process_requests', 9 );
209 +// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Only checking for the data being present.
210 +if ( isset( $_GET['share'] ) ) {
211 + add_action( 'template_redirect', __NAMESPACE__ . '\sharing_process_requests', 9 );
212 +}
213 +
214 +/**
215 + * Automatically add the Sharing Buttons block to the end of the Single Posts template.
216 + *
217 + * @since 13.2
218 + *
219 + * @param array $hooked_block_types The list of hooked block types.
220 + * @param string $relative_position The relative position of the hooked blocks. Can be one of 'before', 'after', 'first_child', or 'last_child'.
221 + * @param string $anchor_block_type The anchor block type.
222 + * @param WP_Block_Template|array $context The block template, template part, or pattern that the anchor block belongs to.
223 + *
224 + * @return array
225 + */
226 +function add_block_to_single_posts_template( $hooked_block_types, $relative_position, $anchor_block_type, $context ) {
227 + // Add the block at the end of the post content.
228 + if (
229 + 'after' !== $relative_position
230 + || 'core/post-content' !== $anchor_block_type
231 + ) {
232 + return $hooked_block_types;
233 + }
234 +
235 + // Only automate the addition of the block in block-based themes.
236 + if ( ! wp_is_block_theme() ) {
237 + return $hooked_block_types;
238 + }
239 +
240 + // Proceed if the user has toggled the auto-addition in Jetpack settings.
241 + if ( ! get_option( 'jetpack_sharing_buttons_auto_add' ) ) {
242 + return $hooked_block_types;
243 + }
244 +
245 + /*
246 + * The Sharing module must be disabled.
247 + * We do not want to automatically insert sharing buttons twice.
248 + * On WordPress.com Simple the module is always active so we must check differently.
249 + * There, we check if buttons are enabled on single posts and pages.
250 + */
251 + if ( ( new Host() )->is_wpcom_simple() ) {
252 + if ( ! class_exists( 'Sharing_Service' ) ) {
253 + include_once JETPACK__PLUGIN_DIR . 'modules/sharedaddy/sharing-service.php';
254 + }
255 +
256 + $sharer = new \Sharing_Service();
257 + $global = $sharer->get_global_options();
258 + if (
259 + ! $global['show']
260 + || in_array( 'post', $global['show'], true )
261 + || in_array( 'page', $global['show'], true )
262 + ) {
263 + return $hooked_block_types;
264 + }
265 + } elseif ( ( new Modules() )->is_active( 'sharedaddy' ) ) {
266 + return $hooked_block_types;
267 + }
268 +
269 + // Only hook into page and single post templates.
270 + if (
271 + ! $context instanceof WP_Block_Template
272 + || ! property_exists( $context, 'slug' )
273 + || empty( $context->slug )
274 + || ! preg_match( '/^(page|single)/', $context->slug )
275 + ) {
276 + return $hooked_block_types;
277 + }
278 +
279 + $hooked_block_types[] = PARENT_BLOCK_NAME;
280 + return $hooked_block_types;
281 +}
282 +
283 +/**
284 + * Add default services to the block we add to the post content by default.
285 + *
286 + * @since 13.2
287 + *
288 + * @param array $parsed_hooked_block The parsed block array for the given hooked block type.
289 + * @param string $hooked_block_type The hooked block type name.
290 + * @param string $relative_position The relative position of the hooked block.
291 + * @param array $parsed_anchor_block The anchor block, in parsed block array format.
292 + * @param WP_Block_Template|array $context The block template, template part, or pattern that the anchor block.
293 + *
294 + * @return array
295 + */
296 +function add_default_services_to_block( $parsed_hooked_block, $hooked_block_type, $relative_position, $parsed_anchor_block, $context ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
297 + // Is the hooked block adjacent to the anchor block?
298 + if ( 'after' !== $relative_position ) {
299 + return $parsed_hooked_block;
300 + }
301 +
302 + // Use the icon style by default.
303 + $parsed_hooked_block['attrs']['styleType'] = 'icon';
304 +
305 + // Add default services (inner blocks) to the block.
306 + $parsed_hooked_block['innerBlocks'] = array(
307 + array(
308 + 'blockName' => INNER_BLOCK_NAME,
309 + 'innerContent' => array(),
310 + 'attrs' => array(
311 + 'service' => 'facebook',
312 + 'label' => esc_html__( 'Facebook', 'jetpack' ),
313 + ),
314 + ),
315 + array(
316 + 'blockName' => INNER_BLOCK_NAME,
317 + 'innerContent' => array(),
318 + 'attrs' => array(
319 + 'service' => 'x',
320 + 'label' => esc_html__( 'X', 'jetpack' ),
321 + ),
322 + ),
323 + array(
324 + 'blockName' => INNER_BLOCK_NAME,
325 + 'innerContent' => array(),
326 + 'attrs' => array(
327 + 'service' => 'mastodon',
328 + 'label' => esc_html__( 'Mastodon', 'jetpack' ),
329 + ),
330 + ),
331 + );
332 +
333 + // Wrap inner blocks in our sharing buttons markup.
334 + $parsed_hooked_block['innerContent'] = array(
335 + '<ul class="wp-block-jetpack-sharing-buttons has-normal-icon-size jetpack-sharing-buttons__services-list" id="jetpack-sharing-serivces-list">',
336 + null,
337 + null,
338 + null,
339 + '</ul>',
340 + );
341 +
342 + // Wrap the whole thing in a group block.
343 + return array(
344 + 'blockName' => 'core/group',
345 + 'attrs' => array(
346 + // Does the anchor block have a layout attribute? If so, use it in the group to maintain the same alignment.
347 + 'layout' => $parsed_anchor_block['attrs']['layout'] ?? 'null',
348 + ),
349 + 'innerBlocks' => array( $parsed_hooked_block ),
350 + 'innerContent' => array(
351 + '<div class="wp-block-group">',
352 + null,
353 + '</div>',
354 + ),
355 + );
356 +}