PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 12.3.1
Jetpack – WP Security, Backup, Speed, & Growth v12.3.1
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 / class.jetpack-twitter-cards.php
jetpack Last commit date
3rd-party 3 years ago _inc 2 years ago css 2 years ago extensions 2 years ago images 2 years ago jetpack_vendor 1 year ago json-endpoints 3 years ago modules 1 year ago sal 3 years ago src 3 years ago vendor 2 years ago views 3 years ago CHANGELOG.md 2 years ago LICENSE.txt 5 years ago SECURITY.md 5 years ago class-jetpack-connection-status.php 5 years ago class-jetpack-connection-widget.php 3 years ago class-jetpack-gallery-settings.php 3 years ago class-jetpack-pre-connection-jitms.php 4 years ago class-jetpack-recommendations-banner.php 3 years ago class-jetpack-stats-dashboard-widget.php 3 years ago class-jetpack-wizard-banner.php 5 years ago class-jetpack-xmlrpc-methods.php 3 years ago class.frame-nonce-preview.php 4 years ago class.jetpack-admin.php 2 years ago class.jetpack-affiliate.php 4 years ago class.jetpack-autoupdate.php 3 years ago class.jetpack-bbpress-json-api.compat.php 5 years ago class.jetpack-boost-modules.php 3 years ago class.jetpack-cli.php 3 years ago class.jetpack-client-server.php 4 years ago class.jetpack-connection-banner.php 3 years ago class.jetpack-data.php 5 years ago class.jetpack-gutenberg.php 2 years ago class.jetpack-heartbeat.php 4 years ago class.jetpack-idc.php 4 years ago class.jetpack-modules-list-table.php 3 years ago class.jetpack-network-sites-list-table.php 3 years ago class.jetpack-network.php 3 years ago class.jetpack-plan.php 2 years ago class.jetpack-post-images.php 3 years ago class.jetpack-twitter-cards.php 3 years ago class.jetpack-user-agent.php 3 years ago class.jetpack.php 2 years ago class.json-api-endpoints.php 3 years ago class.json-api.php 2 years ago class.photon.php 3 years ago composer.json 2 years ago enhanced-open-graph.php 3 years ago functions.compat.php 3 years ago functions.cookies.php 5 years ago functions.global.php 3 years ago functions.is-mobile.php 3 years ago functions.opengraph.php 3 years ago functions.photon.php 3 years ago jetpack.php 1 year ago json-api-config.php 3 years ago json-endpoints.php 3 years ago load-jetpack.php 3 years ago locales.php 4 years ago readme.txt 1 year ago uninstall.php 5 years ago wpml-config.xml 3 years ago
class.jetpack-twitter-cards.php
349 lines
1 <?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2 /**
3 * Jetpack Twitter Card handling.
4 *
5 * @package automattic/jetpack
6 */
7
8 /**
9 * Twitter Cards
10 *
11 * Hooks onto the Open Graph protocol and extends it by adding only the tags
12 * we need for twitter cards.
13 *
14 * @see /wp-content/blog-plugins/open-graph.php
15 * @see https://dev.twitter.com/cards/overview
16 */
17 class Jetpack_Twitter_Cards {
18
19 /**
20 * Adds Twitter Card tags.
21 *
22 * @param array $og_tags Existing OG tags.
23 *
24 * @return array OG tags inclusive of Twitter Card output.
25 */
26 public static function twitter_cards_tags( $og_tags ) {
27 global $post;
28 $post_id = ( $post instanceof WP_Post ) ? $post->ID : null;
29
30 /**
31 * Maximum alt text length.
32 *
33 * @see https://developer.twitter.com/en/docs/tweets/optimize-with-cards/overview/summary-card-with-large-image.html
34 */
35 $alt_length = 420;
36
37 if ( post_password_required() ) {
38 return $og_tags;
39 }
40
41 /** This action is documented in class.jetpack.php */
42 if ( apply_filters( 'jetpack_disable_twitter_cards', false ) ) {
43 return $og_tags;
44 }
45
46 /*
47 * These tags apply to any page (home, archives, etc).
48 */
49
50 // If we have information on the author/creator, then include that as well.
51 if ( ! empty( $post ) && ! empty( $post->post_author ) ) {
52 /** This action is documented in modules/sharedaddy/sharing-sources.php */
53 $handle = apply_filters( 'jetpack_sharing_twitter_via', '', $post_id );
54 if ( ! empty( $handle ) && ! self::is_default_site_tag( $handle ) ) {
55 $og_tags['twitter:creator'] = self::sanitize_twitter_user( $handle );
56 }
57 }
58
59 $site_tag = self::site_tag();
60 /** This action is documented in modules/sharedaddy/sharing-sources.php */
61 $site_tag = apply_filters( 'jetpack_sharing_twitter_via', $site_tag, ( is_singular() ? $post_id : null ) );
62 /** This action is documented in modules/sharedaddy/sharing-sources.php */
63 $site_tag = apply_filters( 'jetpack_twitter_cards_site_tag', $site_tag, $og_tags );
64 if ( ! empty( $site_tag ) ) {
65 $og_tags['twitter:site'] = self::sanitize_twitter_user( $site_tag );
66 }
67
68 if ( ! is_singular() || ! empty( $og_tags['twitter:card'] ) ) {
69 /**
70 * Filter the default Twitter card image, used when no image can be found in a post.
71 *
72 * @module sharedaddy
73 *
74 * @since 5.9.0
75 *
76 * @param string $str Default image URL.
77 */
78 $image = apply_filters( 'jetpack_twitter_cards_image_default', '' );
79 if ( ! empty( $image ) ) {
80 $og_tags['twitter:image'] = $image;
81 }
82
83 return $og_tags;
84 }
85
86 $the_title = get_the_title();
87 if ( ! $the_title ) {
88 $the_title = get_bloginfo( 'name' );
89 }
90 $og_tags['twitter:text:title'] = $the_title;
91
92 /*
93 * The following tags only apply to single pages.
94 */
95
96 $card_type = 'summary';
97
98 // Try to give priority to featured images.
99 if ( class_exists( 'Jetpack_PostImages' ) && ! empty( $post_id ) ) {
100 $post_image = Jetpack_PostImages::get_image(
101 $post_id,
102 array(
103 'width' => 144,
104 'height' => 144,
105 )
106 );
107 if ( ! empty( $post_image ) && is_array( $post_image ) ) {
108 // 4096 is the maximum size for an image per https://developer.twitter.com/en/docs/tweets/optimize-with-cards/overview/summary .
109 if (
110 isset( $post_image['src_width'] ) && isset( $post_image['src_height'] )
111 && (int) $post_image['src_width'] <= 4096
112 && (int) $post_image['src_height'] <= 4096
113 ) {
114 // 300x157 is the minimum size for a summary_large_image per https://developer.twitter.com/en/docs/tweets/optimize-with-cards/overview/summary-card-with-large-image .
115 if ( (int) $post_image['src_width'] >= 300 && (int) $post_image['src_height'] >= 157 ) {
116 $card_type = 'summary_large_image';
117 $og_tags['twitter:image'] = esc_url( add_query_arg( 'w', 640, $post_image['src'] ) );
118 } else {
119 $og_tags['twitter:image'] = esc_url( add_query_arg( 'w', 144, $post_image['src'] ) );
120 }
121
122 // Add the alt tag if we have one.
123 if ( ! empty( $post_image['alt_text'] ) ) {
124 // Shorten it if it is too long.
125 if ( strlen( $post_image['alt_text'] ) > $alt_length ) {
126 $og_tags['twitter:image:alt'] = esc_attr( mb_substr( $post_image['alt_text'], 0, $alt_length ) . '' );
127 } else {
128 $og_tags['twitter:image:alt'] = esc_attr( $post_image['alt_text'] );
129 }
130 }
131 }
132 }
133 }
134
135 // Only proceed with media analysis if a featured image has not superseded it already.
136 if ( empty( $og_tags['twitter:image'] ) && empty( $og_tags['twitter:image:src'] ) ) {
137 if ( ! class_exists( 'Jetpack_Media_Summary' ) ) {
138 require_once JETPACK__PLUGIN_DIR . '_inc/lib/class.media-summary.php';
139 }
140
141 // Test again, class should already be auto-loaded in Jetpack.
142 // If not, skip extra media analysis and stick with a summary card.
143 if ( class_exists( 'Jetpack_Media_Summary' ) && ! empty( $post_id ) ) {
144 $extract = Jetpack_Media_Summary::get( $post_id );
145
146 if ( 'gallery' === $extract['type'] ) {
147 list( $og_tags, $card_type ) = self::twitter_cards_define_type_based_on_image_count( $og_tags, $extract );
148 } elseif ( 'video' === $extract['type'] ) {
149 // Leave as summary, but with large pict of poster frame (we know those comply to Twitter's size requirements).
150 $card_type = 'summary_large_image';
151 $og_tags['twitter:image'] = esc_url( add_query_arg( 'w', 640, $extract['image'] ) );
152 } else {
153 list( $og_tags, $card_type ) = self::twitter_cards_define_type_based_on_image_count( $og_tags, $extract );
154 }
155 }
156 }
157
158 $og_tags['twitter:card'] = $card_type;
159
160 // Make sure we have a description for Twitter, their validator isn't happy without some content (single space not valid).
161 if ( ! isset( $og_tags['og:description'] ) || '' === trim( $og_tags['og:description'] ) || __( 'Visit the post for more.', 'jetpack' ) === $og_tags['og:description'] ) { // empty( trim( $og_tags['og:description'] ) ) isn't valid php.
162 $has_creator = ( ! empty( $og_tags['twitter:creator'] ) && '@wordpressdotcom' !== $og_tags['twitter:creator'] ) ? true : false;
163 if ( ! empty( $extract ) && 'video' === $extract['type'] ) { // use $extract['type'] since $card_type is 'summary' for video posts.
164 /* translators: %s is the post author */
165 $og_tags['twitter:description'] = ( $has_creator ) ? sprintf( __( 'Video post by %s.', 'jetpack' ), $og_tags['twitter:creator'] ) : __( 'Video post.', 'jetpack' );
166 } else {
167 /* translators: %s is the post author */
168 $og_tags['twitter:description'] = ( $has_creator ) ? sprintf( __( 'Post by %s.', 'jetpack' ), $og_tags['twitter:creator'] ) : __( 'Visit the post for more.', 'jetpack' );
169 }
170 }
171
172 if ( empty( $og_tags['twitter:image'] ) && empty( $og_tags['twitter:image:src'] ) ) {
173 /** This action is documented in class.jetpack-twitter-cards.php */
174 $image = apply_filters( 'jetpack_twitter_cards_image_default', '' );
175 if ( ! empty( $image ) ) {
176 $og_tags['twitter:image'] = $image;
177 }
178 }
179
180 return $og_tags;
181 }
182
183 /**
184 * Sanitize the Twitter user by normalizing the @.
185 *
186 * @param string $str Twitter user value.
187 *
188 * @return string Twitter user value.
189 */
190 public static function sanitize_twitter_user( $str ) {
191 return '@' . preg_replace( '/^@/', '', $str );
192 }
193
194 /**
195 * Determines if a site tag is one of the default WP.com/Jetpack ones.
196 *
197 * @param string $site_tag Site tag.
198 *
199 * @return bool True if the default site tag is being used.
200 */
201 public static function is_default_site_tag( $site_tag ) {
202 return in_array( $site_tag, array( '@wordpressdotcom', '@jetpack', 'wordpressdotcom', 'jetpack' ), true );
203 }
204
205 /**
206 * Give priority to the creator tag if using the default site tag.
207 *
208 * @param string $site_tag Site tag.
209 * @param array $og_tags OG tags.
210 *
211 * @return string Site tag.
212 */
213 public static function prioritize_creator_over_default_site( $site_tag, $og_tags = array() ) {
214 if ( ! empty( $og_tags['twitter:creator'] ) && self::is_default_site_tag( $site_tag ) ) {
215 return $og_tags['twitter:creator'];
216 }
217 return $site_tag;
218 }
219
220 /**
221 * Define the Twitter Card type based on image count.
222 *
223 * @param array $og_tags Existing OG tags.
224 * @param array $extract Result of the Image Extractor class.
225 *
226 * @return array
227 */
228 public static function twitter_cards_define_type_based_on_image_count( $og_tags, $extract ) {
229 $card_type = 'summary';
230 $img_count = $extract['count']['image'];
231
232 if ( empty( $img_count ) ) {
233
234 // No images, use Blavatar as a thumbnail for the summary type.
235 if ( function_exists( 'blavatar_domain' ) ) {
236 $blavatar_domain = blavatar_domain( site_url() );
237 if ( blavatar_exists( $blavatar_domain ) ) {
238 $og_tags['twitter:image'] = blavatar_url( $blavatar_domain, 'img', 240 );
239 }
240 }
241
242 // Second fall back, Site Logo.
243 if ( empty( $og_tags['twitter:image'] ) && ( function_exists( 'jetpack_has_site_logo' ) && jetpack_has_site_logo() ) ) {
244 $og_tags['twitter:image'] = jetpack_get_site_logo( 'url' );
245 }
246
247 // Third fall back, Site Icon.
248 if ( empty( $og_tags['twitter:image'] ) && has_site_icon() ) {
249 $og_tags['twitter:image'] = get_site_icon_url( '240' );
250 }
251
252 // Not falling back on Gravatar, because there's no way to know if we end up with an auto-generated one.
253
254 } elseif ( $img_count && ( 'image' === $extract['type'] || 'gallery' === $extract['type'] ) ) {
255 // Test for $extract['type'] to limit to image and gallery, so we don't send a potential fallback image like a Gravatar as a photo post.
256 $card_type = 'summary_large_image';
257 $og_tags['twitter:image'] = esc_url( add_query_arg( 'w', 1400, ( empty( $extract['images'] ) ) ? $extract['image'] : $extract['images'][0]['url'] ) );
258 }
259
260 return array( $og_tags, $card_type );
261 }
262
263 /**
264 * Updates the Twitter Card output.
265 *
266 * @param string $og_tag A single OG tag.
267 *
268 * @return string Result of the OG tag.
269 */
270 public static function twitter_cards_output( $og_tag ) {
271 return ( false !== strpos( $og_tag, 'twitter:' ) ) ? preg_replace( '/property="([^"]+)"/', 'name="\1"', $og_tag ) : $og_tag;
272 }
273
274 /**
275 * Adds settings section and field.
276 */
277 public static function settings_init() {
278 add_settings_section( 'jetpack-twitter-cards-settings', 'Twitter Cards', '__return_false', 'sharing' );
279 add_settings_field(
280 'jetpack-twitter-cards-site-tag',
281 __( 'Twitter Site Tag', 'jetpack' ),
282 array( __CLASS__, 'settings_field' ),
283 'sharing',
284 'jetpack-twitter-cards-settings',
285 array(
286 'label_for' => 'jetpack-twitter-cards-site-tag',
287 )
288 );
289 }
290
291 /**
292 * Add global sharing options.
293 */
294 public static function sharing_global_options() {
295 do_settings_fields( 'sharing', 'jetpack-twitter-cards-settings' );
296 }
297
298 /**
299 * Get the Twitter Via tag.
300 *
301 * @return string Twitter via tag.
302 */
303 public static function site_tag() {
304 $site_tag = ( defined( 'IS_WPCOM' ) && IS_WPCOM ) ?
305 trim( get_option( 'twitter_via' ) ) :
306 Jetpack_Options::get_option_and_ensure_autoload( 'jetpack-twitter-cards-site-tag', '' );
307 if ( empty( $site_tag ) ) {
308 /** This action is documented in modules/sharedaddy/sharing-sources.php */
309 return apply_filters( 'jetpack_sharing_twitter_via', '', null );
310 }
311 return $site_tag;
312 }
313
314 /**
315 * Output the settings field.
316 */
317 public static function settings_field() {
318 wp_nonce_field( 'jetpack-twitter-cards-settings', 'jetpack_twitter_cards_nonce', false );
319 ?>
320 <input type="text" id="jetpack-twitter-cards-site-tag" class="regular-text" name="jetpack-twitter-cards-site-tag" value="<?php echo esc_attr( get_option( 'jetpack-twitter-cards-site-tag' ) ); ?>" />
321 <p class="description" style="width: auto;"><?php esc_html_e( 'The Twitter username of the owner of this site\'s domain.', 'jetpack' ); ?></p>
322 <?php
323 }
324
325 /**
326 * Validate the settings submission.
327 */
328 public static function settings_validate() {
329 if ( isset( $_POST['jetpack_twitter_cards_nonce'] ) && wp_verify_nonce( $_POST['jetpack_twitter_cards_nonce'], 'jetpack-twitter-cards-settings' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
330 update_option( 'jetpack-twitter-cards-site-tag', isset( $_POST['jetpack-twitter-cards-site-tag'] ) ? trim( ltrim( wp_strip_all_tags( filter_var( wp_unslash( $_POST['jetpack-twitter-cards-site-tag'] ) ) ), '@' ) ) : '' );
331 }
332 }
333
334 /**
335 * Initiates the class.
336 */
337 public static function init() {
338 add_filter( 'jetpack_open_graph_tags', array( __CLASS__, 'twitter_cards_tags' ), 11 ); // $priority=11: this should hook into jetpack_open_graph_tags after 'class.jetpack-seo.php' has done so.
339 add_filter( 'jetpack_open_graph_output', array( __CLASS__, 'twitter_cards_output' ) );
340 add_filter( 'jetpack_twitter_cards_site_tag', array( __CLASS__, 'site_tag' ), -99 );
341 add_filter( 'jetpack_twitter_cards_site_tag', array( __CLASS__, 'prioritize_creator_over_default_site' ), 99, 2 );
342 add_action( 'admin_init', array( __CLASS__, 'settings_init' ) );
343 add_action( 'sharing_global_options', array( __CLASS__, 'sharing_global_options' ) );
344 add_action( 'sharing_admin_update', array( __CLASS__, 'settings_validate' ) );
345 }
346 }
347
348 Jetpack_Twitter_Cards::init();
349