Automattic /
jetpack
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | /** |
||
| 3 | * Class Jetpack_Media_Summary |
||
| 4 | * |
||
| 5 | * embed [video] > gallery > image > text |
||
| 6 | */ |
||
| 7 | class Jetpack_Media_Summary { |
||
| 8 | |||
| 9 | private static $cache = array(); |
||
| 10 | |||
| 11 | static function get( $post_id, $blog_id = 0, $args = array() ) { |
||
| 12 | |||
| 13 | $defaults = array( |
||
| 14 | 'max_words' => 16, |
||
| 15 | 'max_chars' => 256, |
||
| 16 | ); |
||
| 17 | $args = wp_parse_args( $args, $defaults ); |
||
| 18 | |||
| 19 | $switched = false; |
||
| 20 | if ( !empty( $blog_id ) && $blog_id != get_current_blog_id() && function_exists( 'switch_to_blog' ) ) { |
||
| 21 | switch_to_blog( $blog_id ); |
||
| 22 | $switched = true; |
||
| 23 | } else { |
||
| 24 | $blog_id = get_current_blog_id(); |
||
| 25 | } |
||
| 26 | |||
| 27 | $cache_key = "{$blog_id}_{$post_id}_{$args['max_words']}_{$args['max_chars']}"; |
||
| 28 | if ( isset( self::$cache[ $cache_key ] ) ) { |
||
| 29 | return self::$cache[ $cache_key ]; |
||
| 30 | } |
||
| 31 | |||
| 32 | if ( ! class_exists( 'Jetpack_Media_Meta_Extractor' ) ) { |
||
| 33 | if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) { |
||
| 34 | jetpack_require_lib( 'class.wpcom-media-meta-extractor' ); |
||
| 35 | } else { |
||
| 36 | jetpack_require_lib( 'class.media-extractor' ); |
||
| 37 | } |
||
| 38 | } |
||
| 39 | |||
| 40 | $post = get_post( $post_id ); |
||
| 41 | $permalink = get_permalink( $post_id ); |
||
| 42 | |||
| 43 | $return = array( |
||
| 44 | 'type' => 'standard', |
||
| 45 | 'permalink' => $permalink, |
||
| 46 | 'image' => '', |
||
| 47 | 'excerpt' => '', |
||
| 48 | 'word_count' => 0, |
||
| 49 | 'secure' => array( |
||
| 50 | 'image' => '', |
||
| 51 | ), |
||
| 52 | 'count' => array( |
||
| 53 | 'image' => 0, |
||
| 54 | 'video' => 0, |
||
| 55 | 'word' => 0, |
||
| 56 | 'link' => 0, |
||
| 57 | ), |
||
| 58 | ); |
||
| 59 | |||
| 60 | if ( empty( $post->post_password ) ) { |
||
| 61 | $return['excerpt'] = self::get_excerpt( $post->post_content, $post->post_excerpt, $args['max_words'], $args['max_chars'] , $post); |
||
| 62 | $return['count']['word'] = self::get_word_count( $post->post_content ); |
||
| 63 | $return['count']['word_remaining'] = self::get_word_remaining_count( $post->post_content, $return['excerpt'] ); |
||
| 64 | $return['count']['link'] = self::get_link_count( $post->post_content ); |
||
| 65 | } |
||
| 66 | |||
| 67 | $extract = Jetpack_Media_Meta_Extractor::extract( $blog_id, $post_id, Jetpack_Media_Meta_Extractor::ALL ); |
||
| 68 | |||
| 69 | if ( empty( $extract['has'] ) ) |
||
| 70 | return $return; |
||
| 71 | |||
| 72 | // Prioritize [some] video embeds |
||
| 73 | if ( !empty( $extract['has']['shortcode'] ) ) { |
||
| 74 | foreach ( $extract['shortcode'] as $type => $data ) { |
||
| 75 | switch ( $type ) { |
||
| 76 | case 'videopress': |
||
| 77 | case 'wpvideo': |
||
| 78 | if ( 0 == $return['count']['video'] ) { |
||
| 79 | // If there is no id on the video, then let's just skip this |
||
| 80 | if ( ! isset ( $data['id'][0] ) ) { |
||
| 81 | break; |
||
| 82 | } |
||
| 83 | |||
| 84 | $guid = $data['id'][0]; |
||
| 85 | $video_info = videopress_get_video_details( $guid ); |
||
| 86 | |||
| 87 | // Only add the video tags if the guid returns a valid videopress object. |
||
| 88 | if ( $video_info instanceof stdClass ) { |
||
| 89 | // Continue early if we can't find a Video slug. |
||
| 90 | if ( empty( $video_info->files->std->mp4 ) ) { |
||
| 91 | break; |
||
| 92 | } |
||
| 93 | |||
| 94 | $url = sprintf( |
||
| 95 | 'https://videos.files.wordpress.com/%1$s/%2$s', |
||
| 96 | $guid, |
||
| 97 | $video_info->files->std->mp4 |
||
| 98 | ); |
||
| 99 | |||
| 100 | $thumbnail = $video_info->poster; |
||
| 101 | if ( ! empty( $thumbnail ) ) { |
||
| 102 | $return['image'] = $thumbnail; |
||
| 103 | $return['secure']['image'] = $thumbnail; |
||
| 104 | } |
||
| 105 | |||
| 106 | $return['type'] = 'video'; |
||
| 107 | $return['video'] = esc_url_raw( $url ); |
||
| 108 | $return['video_type'] = 'video/mp4'; |
||
| 109 | $return['secure']['video'] = $return['video']; |
||
| 110 | } |
||
| 111 | |||
| 112 | } |
||
| 113 | $return['count']['video']++; |
||
| 114 | break; |
||
| 115 | case 'youtube': |
||
| 116 | if ( 0 == $return['count']['video'] ) { |
||
| 117 | $return['type'] = 'video'; |
||
| 118 | $return['video'] = esc_url_raw( 'http://www.youtube.com/watch?feature=player_embedded&v=' . $extract['shortcode']['youtube']['id'][0] ); |
||
| 119 | $return['image'] = self::get_video_poster( 'youtube', $extract['shortcode']['youtube']['id'][0] ); |
||
| 120 | $return['secure']['video'] = self::https( $return['video'] ); |
||
| 121 | $return['secure']['image'] = self::https( $return['image'] ); |
||
| 122 | } |
||
| 123 | $return['count']['video']++; |
||
| 124 | break; |
||
| 125 | case 'vimeo': |
||
| 126 | if ( 0 == $return['count']['video'] ) { |
||
| 127 | $return['type'] = 'video'; |
||
| 128 | $return['video'] = esc_url_raw( 'http://vimeo.com/' . $extract['shortcode']['vimeo']['id'][0] ); |
||
| 129 | $return['secure']['video'] = self::https( $return['video'] ); |
||
| 130 | |||
| 131 | $poster_image = get_post_meta( $post_id, 'vimeo_poster_image', true ); |
||
| 132 | View Code Duplication | if ( !empty( $poster_image ) ) { |
|
| 133 | $return['image'] = $poster_image; |
||
| 134 | $poster_url_parts = wp_parse_url( $poster_image ); |
||
| 135 | $return['secure']['image'] = 'https://secure-a.vimeocdn.com' . $poster_url_parts['path']; |
||
| 136 | } |
||
| 137 | } |
||
| 138 | $return['count']['video']++; |
||
| 139 | break; |
||
| 140 | } |
||
| 141 | } |
||
| 142 | |||
| 143 | } |
||
| 144 | |||
| 145 | if ( !empty( $extract['has']['embed'] ) ) { |
||
| 146 | foreach( $extract['embed']['url'] as $embed ) { |
||
| 147 | if ( preg_match( '/((youtube|vimeo|dailymotion)\.com|youtu.be)/', $embed ) ) { |
||
| 148 | if ( 0 == $return['count']['video'] ) { |
||
| 149 | $return['type'] = 'video'; |
||
| 150 | $return['video'] = 'http://' . $embed; |
||
| 151 | $return['secure']['video'] = self::https( $return['video'] ); |
||
| 152 | if ( false !== strpos( $embed, 'youtube' ) ) { |
||
| 153 | $return['image'] = self::get_video_poster( 'youtube', jetpack_get_youtube_id( $return['video'] ) ); |
||
| 154 | $return['secure']['image'] = self::https( $return['image'] ); |
||
| 155 | } else if ( false !== strpos( $embed, 'youtu.be' ) ) { |
||
| 156 | $youtube_id = jetpack_get_youtube_id( $return['video'] ); |
||
| 157 | $return['video'] = 'http://youtube.com/watch?v=' . $youtube_id . '&feature=youtu.be'; |
||
| 158 | $return['secure']['video'] = self::https( $return['video'] ); |
||
| 159 | $return['image'] = self::get_video_poster( 'youtube', jetpack_get_youtube_id( $return['video'] ) ); |
||
| 160 | $return['secure']['image'] = self::https( $return['image'] ); |
||
| 161 | } else if ( false !== strpos( $embed, 'vimeo' ) ) { |
||
| 162 | $poster_image = get_post_meta( $post_id, 'vimeo_poster_image', true ); |
||
| 163 | View Code Duplication | if ( !empty( $poster_image ) ) { |
|
| 164 | $return['image'] = $poster_image; |
||
| 165 | $poster_url_parts = wp_parse_url( $poster_image ); |
||
| 166 | $return['secure']['image'] = 'https://secure-a.vimeocdn.com' . $poster_url_parts['path']; |
||
| 167 | } |
||
| 168 | } else if ( false !== strpos( $embed, 'dailymotion' ) ) { |
||
| 169 | $return['image'] = str_replace( 'dailymotion.com/video/','dailymotion.com/thumbnail/video/', $embed ); |
||
| 170 | $return['image'] = wp_parse_url( $return['image'], PHP_URL_SCHEME ) === null ? 'http://' . $return['image'] : $return['image']; |
||
|
0 ignored issues
–
show
|
|||
| 171 | $return['secure']['image'] = self::https( $return['image'] ); |
||
| 172 | } |
||
| 173 | |||
| 174 | } |
||
| 175 | $return['count']['video']++; |
||
| 176 | } |
||
| 177 | } |
||
| 178 | } |
||
| 179 | |||
| 180 | // Do we really want to make the video the primary focus of the post? |
||
| 181 | if ( 'video' == $return['type'] ) { |
||
| 182 | $content = wpautop( strip_tags( $post->post_content ) ); |
||
| 183 | $paragraphs = explode( '</p>', $content ); |
||
| 184 | $number_of_paragraphs = 0; |
||
| 185 | |||
| 186 | foreach ( $paragraphs as $i => $paragraph ) { |
||
| 187 | // Don't include blank lines as a paragraph |
||
| 188 | if ( '' == trim( $paragraph ) ) { |
||
| 189 | unset( $paragraphs[$i] ); |
||
| 190 | continue; |
||
| 191 | } |
||
| 192 | $number_of_paragraphs++; |
||
| 193 | } |
||
| 194 | |||
| 195 | $number_of_paragraphs = $number_of_paragraphs - $return['count']['video']; // subtract amount for videos.. |
||
| 196 | |||
| 197 | // More than 2 paragraph? The video is not the primary focus so we can do some more analysis |
||
| 198 | if ( $number_of_paragraphs > 2 ) |
||
| 199 | $return['type'] = 'standard'; |
||
| 200 | } |
||
| 201 | |||
| 202 | // If we don't have any prioritized embed... |
||
| 203 | if ( 'standard' == $return['type'] ) { |
||
| 204 | if ( ( ! empty( $extract['has']['gallery'] ) || ! empty( $extract['shortcode']['gallery']['count'] ) ) && ! empty( $extract['image'] ) ) { |
||
| 205 | //... Then we prioritize galleries first (multiple images returned) |
||
| 206 | $return['type'] = 'gallery'; |
||
| 207 | $return['images'] = $extract['image']; |
||
| 208 | foreach ( $return['images'] as $image ) { |
||
| 209 | $return['secure']['images'][] = array( 'url' => self::ssl_img( $image['url'] ) ); |
||
| 210 | $return['count']['image']++; |
||
| 211 | } |
||
| 212 | } else if ( ! empty( $extract['has']['image'] ) ) { |
||
| 213 | // ... Or we try and select a single image that would make sense |
||
| 214 | $content = wpautop( strip_tags( $post->post_content ) ); |
||
| 215 | $paragraphs = explode( '</p>', $content ); |
||
| 216 | $number_of_paragraphs = 0; |
||
| 217 | |||
| 218 | foreach ( $paragraphs as $i => $paragraph ) { |
||
| 219 | // Don't include 'actual' captions as a paragraph |
||
| 220 | if ( false !== strpos( $paragraph, '[caption' ) ) { |
||
| 221 | unset( $paragraphs[$i] ); |
||
| 222 | continue; |
||
| 223 | } |
||
| 224 | // Don't include blank lines as a paragraph |
||
| 225 | if ( '' == trim( $paragraph ) ) { |
||
| 226 | unset( $paragraphs[$i] ); |
||
| 227 | continue; |
||
| 228 | } |
||
| 229 | $number_of_paragraphs++; |
||
| 230 | } |
||
| 231 | |||
| 232 | $return['image'] = $extract['image'][0]['url']; |
||
| 233 | $return['secure']['image'] = self::ssl_img( $return['image'] ); |
||
| 234 | $return['count']['image']++; |
||
| 235 | |||
| 236 | if ( $number_of_paragraphs <= 2 && 1 == count( $extract['image'] ) ) { |
||
| 237 | // If we have lots of text or images, let's not treat it as an image post, but return its first image |
||
| 238 | $return['type'] = 'image'; |
||
| 239 | } |
||
| 240 | } |
||
| 241 | } |
||
| 242 | |||
| 243 | if ( $switched ) { |
||
| 244 | restore_current_blog(); |
||
| 245 | } |
||
| 246 | |||
| 247 | /** |
||
| 248 | * Allow a theme or plugin to inspect and ultimately change the media summary. |
||
| 249 | * |
||
| 250 | * @since 4.4.0 |
||
| 251 | * |
||
| 252 | * @param array $data The calculated media summary data. |
||
| 253 | * @param int $post_id The id of the post this data applies to. |
||
| 254 | */ |
||
| 255 | $return = apply_filters( 'jetpack_media_summary_output', $return, $post_id ); |
||
| 256 | |||
| 257 | self::$cache[ $cache_key ] = $return; |
||
| 258 | |||
| 259 | return $return; |
||
| 260 | } |
||
| 261 | |||
| 262 | static function https( $str ) { |
||
| 263 | return str_replace( 'http://', 'https://', $str ); |
||
| 264 | } |
||
| 265 | |||
| 266 | static function ssl_img( $url ) { |
||
| 267 | if ( false !== strpos( $url, 'files.wordpress.com' ) ) { |
||
| 268 | return self::https( $url ); |
||
| 269 | } else { |
||
| 270 | return self::https( jetpack_photon_url( $url ) ); |
||
| 271 | } |
||
| 272 | } |
||
| 273 | |||
| 274 | static function get_video_poster( $type, $id ) { |
||
| 275 | if ( 'videopress' == $type ) { |
||
| 276 | if ( function_exists( 'video_get_highest_resolution_image_url' ) ) { |
||
| 277 | return video_get_highest_resolution_image_url( $id ); |
||
| 278 | } else if ( class_exists( 'VideoPress_Video' ) ) { |
||
| 279 | $video = new VideoPress_Video( $id ); |
||
| 280 | return $video->poster_frame_uri; |
||
| 281 | } |
||
| 282 | } else if ( 'youtube' == $type ) { |
||
| 283 | return 'http://img.youtube.com/vi/'.$id.'/0.jpg'; |
||
| 284 | } |
||
| 285 | } |
||
| 286 | |||
| 287 | static function clean_text( $text ) { |
||
| 288 | return trim( |
||
| 289 | preg_replace( |
||
| 290 | '/[\s]+/', |
||
| 291 | ' ', |
||
| 292 | preg_replace( |
||
| 293 | '@https?://[\S]+@', |
||
| 294 | '', |
||
| 295 | strip_shortcodes( |
||
| 296 | strip_tags( |
||
| 297 | $text |
||
| 298 | ) |
||
| 299 | ) |
||
| 300 | ) |
||
| 301 | ) |
||
| 302 | ); |
||
| 303 | } |
||
| 304 | |||
| 305 | /** |
||
| 306 | * Retrieve an excerpt for the post summary. |
||
| 307 | * |
||
| 308 | * This function works around a suspected problem with Core. If resolved, this function should be simplified. |
||
| 309 | * @link https://github.com/Automattic/jetpack/pull/8510 |
||
| 310 | * @link https://core.trac.wordpress.org/ticket/42814 |
||
| 311 | * |
||
| 312 | * @param string $post_content The post's content. |
||
| 313 | * @param string $post_excerpt The post's excerpt. Empty if none was explicitly set. |
||
| 314 | * @param int $max_words Maximum number of words for the excerpt. Used on wp.com. Default 16. |
||
| 315 | * @param int $max_chars Maximum characters in the excerpt. Used on wp.com. Default 256. |
||
| 316 | * @param WP_Post $requested_post The post object. |
||
| 317 | * @return string Post excerpt. |
||
| 318 | **/ |
||
| 319 | static function get_excerpt( $post_content, $post_excerpt, $max_words = 16, $max_chars = 256, $requested_post = null ) { |
||
| 320 | global $post; |
||
| 321 | $original_post = $post; // Saving the global for later use. |
||
| 322 | if ( function_exists( 'wpcom_enhanced_excerpt_extract_excerpt' ) ) { |
||
| 323 | return self::clean_text( wpcom_enhanced_excerpt_extract_excerpt( array( |
||
| 324 | 'text' => $post_content, |
||
| 325 | 'excerpt_only' => true, |
||
| 326 | 'show_read_more' => false, |
||
| 327 | 'max_words' => $max_words, |
||
| 328 | 'max_chars' => $max_chars, |
||
| 329 | 'read_more_threshold' => 25, |
||
| 330 | ) ) ); |
||
| 331 | } elseif ( $requested_post instanceof WP_Post ) { |
||
| 332 | $post = $requested_post; // setup_postdata does not set the global. |
||
| 333 | setup_postdata( $post ); |
||
| 334 | /** This filter is documented in core/src/wp-includes/post-template.php */ |
||
| 335 | $post_excerpt = apply_filters( 'get_the_excerpt', $post_excerpt, $post ); |
||
| 336 | $post = $original_post; // wp_reset_postdata uses the $post global. |
||
| 337 | wp_reset_postdata(); |
||
| 338 | return self::clean_text( $post_excerpt ); |
||
| 339 | } |
||
| 340 | return ''; |
||
| 341 | } |
||
| 342 | |||
| 343 | /** |
||
| 344 | * Split a string into an array of words. |
||
| 345 | * |
||
| 346 | * @param string $text Post content or excerpt. |
||
| 347 | */ |
||
| 348 | static function split_content_in_words( $text ) { |
||
| 349 | $words = preg_split( '/[\s!?;,.]+/', $text, null, PREG_SPLIT_NO_EMPTY ); |
||
| 350 | |||
| 351 | // Return an empty array if the split above fails. |
||
| 352 | return $words ? $words : array(); |
||
| 353 | } |
||
| 354 | |||
| 355 | static function get_word_count( $post_content ) { |
||
| 356 | return (int) count( self::split_content_in_words( self::clean_text( $post_content ) ) ); |
||
| 357 | } |
||
| 358 | |||
| 359 | static function get_word_remaining_count( $post_content, $excerpt_content ) { |
||
| 360 | $content_word_count = count( self::split_content_in_words( self::clean_text( $post_content ) ) ); |
||
| 361 | $excerpt_word_count = count( self::split_content_in_words( self::clean_text( $excerpt_content ) ) ); |
||
| 362 | |||
| 363 | return (int) $content_word_count - $excerpt_word_count; |
||
| 364 | } |
||
| 365 | |||
| 366 | static function get_link_count( $post_content ) { |
||
| 367 | return preg_match_all( '/\<a[\> ]/', $post_content, $matches ); |
||
| 368 | } |
||
| 369 | } |
||
| 370 |
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.
In this case you can add the
@ignorePhpDoc annotation to the duplicate definition and it will be ignored.