| @@ -10,8 +10,12 @@ | ||
| 10 | 10 | */ |
| 11 | 11 | |
| 12 | 12 | use Automattic\Jetpack\Status; |
| 13 | 13 | |
| 14 | +if ( ! defined( 'ABSPATH' ) ) { | |
| 15 | + exit( 0 ); | |
| 16 | +} | |
| 17 | + | |
| 14 | 18 | require_once __DIR__ . '/class.json-api-metadata.php'; |
| 15 | 19 | require_once __DIR__ . '/class.json-api-date.php'; |
| 16 | 20 | require_once ABSPATH . 'wp-admin/includes/post.php'; |
| 17 | 21 | require_once ABSPATH . 'wp-includes/post.php'; |
| @@ -358,9 +362,9 @@ | ||
| 358 | 362 | ); |
| 359 | 363 | } |
| 360 | 364 | |
| 361 | 365 | /** |
| 362 | - * Returns an array with details of the posts revisions, or false if 'edit' isn't the current post request context. | |
| 366 | + * Returns an array with post revision ids, or false if 'edit' isn't the current post request context. | |
| 363 | 367 | * |
| 364 | 368 | * @return bool|array |
| 365 | 369 | */ |
| 366 | 370 | public function get_revisions() { |
| @@ -367,16 +371,18 @@ | ||
| 367 | 371 | if ( 'edit' !== $this->context ) { |
| 368 | 372 | return false; |
| 369 | 373 | } |
| 370 | 374 | |
| 371 | - $revisions = array(); | |
| 372 | - $post_revisions = wp_get_post_revisions( $this->post->ID ); | |
| 375 | + $args = array( | |
| 376 | + 'posts_per_page' => -1, | |
| 377 | + 'post_type' => 'revision', | |
| 378 | + 'post_status' => 'any', | |
| 379 | + 'fields' => 'ids', // Fetch only the IDs. | |
| 380 | + 'post_parent' => $this->post->ID, | |
| 381 | + ); | |
| 373 | 382 | |
| 374 | - foreach ( $post_revisions as $_post ) { | |
| 375 | - $revisions[] = $_post->ID; | |
| 376 | - } | |
| 377 | - | |
| 378 | - return $revisions; | |
| 383 | + $revision_query = new WP_Query( $args ); | |
| 384 | + return $revision_query->posts; // This returns an array of revision IDs. | |
| 379 | 385 | } |
| 380 | 386 | |
| 381 | 387 | /** |
| 382 | 388 | * Returns an object with extra post permalink suggestions. |
| @@ -420,25 +426,44 @@ | ||
| 420 | 426 | public function get_publicize_urls() { |
| 421 | 427 | $publicize_urls = array(); |
| 422 | 428 | $publicize = get_post_meta( $this->post->ID, 'publicize_results', true ); |
| 423 | 429 | if ( $publicize ) { |
| 424 | - foreach ( $publicize as $service => $data ) { | |
| 425 | - switch ( $service ) { | |
| 426 | - // @todo explore removing once Twitter is removed from Publicize. | |
| 427 | - case 'twitter': | |
| 428 | - foreach ( $data as $datum ) { | |
| 429 | - $publicize_urls[] = esc_url_raw( "https://twitter.com/{$datum['user_id']}/status/{$datum['post_id']}" ); | |
| 430 | - } | |
| 431 | - break; | |
| 432 | - case 'fb': | |
| 433 | - foreach ( $data as $datum ) { | |
| 434 | - $publicize_urls[] = esc_url_raw( "https://www.facebook.com/permalink.php?story_fbid={$datum['post_id']}&id={$datum['user_id']}" ); | |
| 435 | - } | |
| 436 | - break; | |
| 430 | + // get_post_meta(..., true) will return a string if the value was stored as a scalar or serialized, so we may need to unserialize. | |
| 431 | + if ( is_string( $publicize ) ) { | |
| 432 | + $maybe_array_publicize = maybe_unserialize( $publicize ); | |
| 433 | + if ( ! is_array( $maybe_array_publicize ) ) { | |
| 434 | + $maybe_array_publicize = json_decode( $publicize, true ); | |
| 437 | 435 | } |
| 436 | + if ( is_array( $maybe_array_publicize ) ) { | |
| 437 | + $publicize = $maybe_array_publicize; | |
| 438 | + } else { | |
| 439 | + return $publicize_urls; | |
| 440 | + } | |
| 438 | 441 | } |
| 442 | + | |
| 443 | + if ( is_array( $publicize ) ) { | |
| 444 | + foreach ( $publicize as $service => $data ) { | |
| 445 | + switch ( $service ) { | |
| 446 | + // @todo explore removing once Twitter is removed from Publicize. | |
| 447 | + case 'twitter': | |
| 448 | + foreach ( $data as $datum ) { | |
| 449 | + if ( isset( $datum['user_id'] ) && isset( $datum['post_id'] ) ) { | |
| 450 | + $publicize_urls[] = esc_url_raw( "https://twitter.com/{$datum['user_id']}/status/{$datum['post_id']}" ); | |
| 451 | + } | |
| 452 | + } | |
| 453 | + break; | |
| 454 | + case 'fb': | |
| 455 | + foreach ( $data as $datum ) { | |
| 456 | + if ( isset( $datum['user_id'] ) && isset( $datum['post_id'] ) ) { | |
| 457 | + $publicize_urls[] = esc_url_raw( "https://www.facebook.com/permalink.php?story_fbid={$datum['post_id']}&id={$datum['user_id']}" ); | |
| 458 | + } | |
| 459 | + } | |
| 460 | + break; | |
| 461 | + } | |
| 462 | + } | |
| 463 | + } | |
| 439 | 464 | } |
| 440 | - return (array) $publicize_urls; | |
| 465 | + return $publicize_urls; | |
| 441 | 466 | } |
| 442 | 467 | |
| 443 | 468 | /** |
| 444 | 469 | * Returns a string with the page's custom template metadata. |
| @@ -555,9 +580,9 @@ | ||
| 555 | 580 | public function get_title() { |
| 556 | 581 | if ( 'display' === $this->context ) { |
| 557 | 582 | return (string) get_the_title( $this->post->ID ); |
| 558 | 583 | } else { |
| 559 | - return (string) htmlspecialchars_decode( $this->post->post_title, ENT_QUOTES ); | |
| 584 | + return htmlspecialchars_decode( $this->post->post_title, ENT_QUOTES ); | |
| 560 | 585 | } |
| 561 | 586 | } |
| 562 | 587 | |
| 563 | 588 | /** |
| @@ -651,14 +676,23 @@ | ||
| 651 | 676 | */ |
| 652 | 677 | public function get_password() { |
| 653 | 678 | $password = (string) $this->post->post_password; |
| 654 | 679 | if ( 'edit' === $this->context ) { |
| 655 | - $password = htmlspecialchars_decode( (string) $password, ENT_QUOTES ); | |
| 680 | + $password = htmlspecialchars_decode( $password, ENT_QUOTES ); | |
| 656 | 681 | } |
| 657 | 682 | return $password; |
| 658 | 683 | } |
| 659 | 684 | |
| 660 | 685 | /** |
| 686 | + * Returns true if the post has a password set, regardless of whether the current user can view or receive the password value. | |
| 687 | + * | |
| 688 | + * @return bool | |
| 689 | + */ | |
| 690 | + public function get_has_password(): bool { | |
| 691 | + return strlen( (string) $this->post->post_password ) > 0; | |
| 692 | + } | |
| 693 | + | |
| 694 | + /** | |
| 661 | 695 | * Returns an object representing a post's parent, and false if it doesn't have one. |
| 662 | 696 | * |
| 663 | 697 | * @return object|bool |
| 664 | 698 | */ |
| @@ -664,12 +698,15 @@ | ||
| 664 | 698 | */ |
| 665 | 699 | public function get_parent() { |
| 666 | 700 | if ( $this->post->post_parent ) { |
| 667 | 701 | $parent = get_post( $this->post->post_parent ); |
| 702 | + if ( ! $parent ) { | |
| 703 | + return false; | |
| 704 | + } | |
| 668 | 705 | if ( 'display' === $this->context ) { |
| 669 | 706 | $parent_title = (string) get_the_title( $parent->ID ); |
| 670 | 707 | } else { |
| 671 | - $parent_title = (string) htmlspecialchars_decode( $this->post->post_title, ENT_QUOTES ); | |
| 708 | + $parent_title = htmlspecialchars_decode( $this->post->post_title, ENT_QUOTES ); | |
| 672 | 709 | } |
| 673 | 710 | return (object) array( |
| 674 | 711 | 'ID' => (int) $parent->ID, |
| 675 | 712 | 'type' => (string) $parent->post_type, |
| @@ -788,12 +825,12 @@ | ||
| 788 | 825 | // @todo: factor this out |
| 789 | 826 | // phpcs:disable WordPress.NamingConventions.ValidVariableName |
| 790 | 827 | if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) { |
| 791 | 828 | $active_blog = get_active_blog_for_user( $user->ID ); |
| 792 | - $site_id = $active_blog->blog_id; | |
| 793 | - $profile_URL = "https://en.gravatar.com/{$user->user_login}"; | |
| 829 | + $site_id = $active_blog->blog_id ?? -1; | |
| 830 | + $profile_URL = "https://gravatar.com/{$user->user_login}"; | |
| 794 | 831 | } else { |
| 795 | - $profile_URL = 'https://en.gravatar.com/' . md5( strtolower( trim( $user->user_email ) ) ); | |
| 832 | + $profile_URL = 'https://gravatar.com/' . md5( strtolower( trim( $user->user_email ) ) ); | |
| 796 | 833 | $site_id = -1; |
| 797 | 834 | } |
| 798 | 835 | |
| 799 | 836 | $author = array( |
| @@ -822,12 +859,14 @@ | ||
| 822 | 859 | * |
| 823 | 860 | * @param string $email The user's email. |
| 824 | 861 | * @param int $avatar_size The size of the avatar in pixels. |
| 825 | 862 | * |
| 863 | + * @todo Provide a non-WP.com option. | |
| 864 | + * | |
| 826 | 865 | * @return string |
| 827 | 866 | */ |
| 828 | 867 | protected function get_avatar_url( $email, $avatar_size = 96 ) { |
| 829 | - $avatar_url = wpcom_get_avatar_url( $email, $avatar_size, '', true ); | |
| 868 | + $avatar_url = function_exists( 'wpcom_get_avatar_url' ) ? wpcom_get_avatar_url( $email, $avatar_size ) : ''; | |
| 830 | 869 | if ( ! $avatar_url || is_wp_error( $avatar_url ) ) { |
| 831 | 870 | return ''; |
| 832 | 871 | } |
| 833 | 872 | |
| @@ -914,9 +953,9 @@ | ||
| 914 | 953 | } |
| 915 | 954 | |
| 916 | 955 | $file = basename( wp_get_attachment_url( $media_item->ID ) ); |
| 917 | 956 | $file_info = pathinfo( $file ); |
| 918 | - $ext = $file_info['extension']; | |
| 957 | + $ext = $file_info['extension'] ?? ''; | |
| 919 | 958 | |
| 920 | 959 | $response = array( |
| 921 | 960 | 'ID' => $media_item->ID, |
| 922 | 961 | 'URL' => wp_get_attachment_url( $media_item->ID ), |
| @@ -954,9 +993,11 @@ | ||
| 954 | 993 | */ |
| 955 | 994 | $sizes = apply_filters( 'rest_api_thumbnail_sizes', $metadata['sizes'], $media_id ); |
| 956 | 995 | if ( is_array( $sizes ) ) { |
| 957 | 996 | foreach ( $sizes as $size => $size_details ) { |
| 958 | - $response['thumbnails'][ $size ] = dirname( $response['URL'] ) . '/' . $size_details['file']; | |
| 997 | + if ( isset( $size_details['file'] ) ) { | |
| 998 | + $response['thumbnails'][ $size ] = dirname( $response['URL'] ) . '/' . $size_details['file']; | |
| 999 | + } | |
| 959 | 1000 | } |
| 960 | 1001 | } |
| 961 | 1002 | } |
| 962 | 1003 | |
| @@ -984,8 +1025,16 @@ | ||
| 984 | 1025 | if ( isset( $metadata['length'] ) ) { |
| 985 | 1026 | $response['length'] = $metadata['length']; |
| 986 | 1027 | } |
| 987 | 1028 | |
| 1029 | + if ( empty( $response['length'] ) && isset( $metadata['duration'] ) ) { | |
| 1030 | + $response['length'] = (int) $metadata['duration']; | |
| 1031 | + } | |
| 1032 | + | |
| 1033 | + if ( empty( $response['length'] ) && isset( $metadata['videopress']['duration'] ) ) { | |
| 1034 | + $response['length'] = ceil( $metadata['videopress']['duration'] / 1000 ); | |
| 1035 | + } | |
| 1036 | + | |
| 988 | 1037 | // add VideoPress info. |
| 989 | 1038 | if ( function_exists( 'video_get_info_by_blogpostid' ) ) { |
| 990 | 1039 | $info = video_get_info_by_blogpostid( $this->site->get_id(), $media_id ); |
| 991 | 1040 | |
| @@ -1004,13 +1053,11 @@ | ||
| 1004 | 1053 | } |
| 1005 | 1054 | } |
| 1006 | 1055 | } |
| 1007 | 1056 | |
| 1008 | - $response['videopress_guid'] = $info->guid; | |
| 1057 | + $response['videopress_guid'] = $info->guid ?? null; | |
| 1009 | 1058 | $response['videopress_processing_done'] = true; |
| 1010 | - if ( '0000-00-00 00:00:00' === $info->finish_date_gmt ) { | |
| 1011 | - $response['videopress_processing_done'] = false; | |
| 1012 | - } | |
| 1059 | + $response['videopress_processing_done'] = isset( $info->finish_date_gmt ) && '0000-00-00 00:00:00' !== $info->finish_date_gmt ? $info->finish_date_gmt : false; | |
| 1013 | 1060 | } |
| 1014 | 1061 | } |
| 1015 | 1062 | |
| 1016 | 1063 | $response['thumbnails'] = (object) $response['thumbnails']; |