diff options
author | 2022-06-15 12:08:35 -0400 | |
---|---|---|
committer | 2022-06-15 12:08:35 -0400 | |
commit | 36d7691c33cb64ece817246e47a779ec648d10b0 (patch) | |
tree | 08f2fb95303a1d8eeba2c8629a24b35a91fb1cac /plugins/jetpack/class.json-api-endpoints.php | |
parent | twentyfourteen upg 2.7 to 3.2 and twentysixteen from 2.0 to 2.5 (diff) | |
download | blogs-gentoo-36d7691c33cb64ece817246e47a779ec648d10b0.tar.gz blogs-gentoo-36d7691c33cb64ece817246e47a779ec648d10b0.tar.bz2 blogs-gentoo-36d7691c33cb64ece817246e47a779ec648d10b0.zip |
Openid-3.6.1 and jetpack-11.0 upgrade
Signed-off-by: Yury German <blueknight@gentoo.org>
Diffstat (limited to 'plugins/jetpack/class.json-api-endpoints.php')
-rw-r--r-- | plugins/jetpack/class.json-api-endpoints.php | 728 |
1 files changed, 537 insertions, 191 deletions
diff --git a/plugins/jetpack/class.json-api-endpoints.php b/plugins/jetpack/class.json-api-endpoints.php index 22aeb295..4ee2d303 100644 --- a/plugins/jetpack/class.json-api-endpoints.php +++ b/plugins/jetpack/class.json-api-endpoints.php @@ -1,53 +1,109 @@ -<?php +<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName +/** + * Jetpack API endpoint base class. + * + * @package automattic/jetpack + */ use Automattic\Jetpack\Connection\Client; -require_once dirname( __FILE__ ) . '/json-api-config.php'; -require_once dirname( __FILE__ ) . '/sal/class.json-api-links.php'; -require_once dirname( __FILE__ ) . '/sal/class.json-api-metadata.php'; -require_once dirname( __FILE__ ) . '/sal/class.json-api-date.php'; +require_once __DIR__ . '/json-api-config.php'; +require_once __DIR__ . '/sal/class.json-api-links.php'; +require_once __DIR__ . '/sal/class.json-api-metadata.php'; +require_once __DIR__ . '/sal/class.json-api-date.php'; -// Endpoint +/** + * Endpoint. + */ abstract class WPCOM_JSON_API_Endpoint { - // The API Object + /** + * The API Object + * + * @var WPCOM_JSON_API + */ public $api; - // The link-generating utility class + /** + * The link-generating utility class + * + * @var WPCOM_JSON_API_Links + */ public $links; + /** + * Whether to pass wpcom user details. + * + * @var bool + */ public $pass_wpcom_user_details = false; - // One liner. + /** + * One liner. + * + * @var string + */ public $description; - // Object Grouping For Documentation (Users, Posts, Comments) + /** + * Object Grouping For Documentation (Users, Posts, Comments) + * + * @var string + */ public $group; - // Stats extra value to bump + /** + * Stats extra value to bump + * + * @var mixed + */ public $stat; - // HTTP Method + /** + * HTTP Method + * + * @var string + */ public $method = 'GET'; - // Minimum version of the api for which to serve this endpoint + /** + * Minimum version of the api for which to serve this endpoint + * + * @var string + */ public $min_version = '0'; - // Maximum version of the api for which to serve this endpoint + /** + * Maximum version of the api for which to serve this endpoint + * + * @var string + */ public $max_version = WPCOM_JSON_API__CURRENT_VERSION; - // Path at which to serve this endpoint: sprintf() format. + /** + * Path at which to serve this endpoint: sprintf() format. + * + * @var string + */ public $path = ''; - // Identifiers to fill sprintf() formatted $path + /** + * Identifiers to fill sprintf() formatted $path + * + * @var array + */ public $path_labels = array(); - // Accepted query parameters + /** + * Accepted query parameters + * + * @var array + */ public $query = array( - // Parameter name + // Parameter name. 'context' => array( - // Default value => description + // Default value => description. 'display' => 'Formats the output as HTML for display. Shortcodes are parsed, paragraph tags are added, etc..', - // Other possible values => description + // Other possible values => description. 'edit' => 'Formats the output for editing. Shortcodes are left unparsed, significant whitespace is kept, etc..', ), 'http_envelope' => array( @@ -60,75 +116,119 @@ abstract class WPCOM_JSON_API_Endpoint { ), 'meta' => "(string) Optional. Loads data from the endpoints found in the 'meta' part of the response. Comma-separated list. Example: meta=site,likes", 'fields' => '(string) Optional. Returns specified fields only. Comma-separated list. Example: fields=ID,title', - // Parameter name => description (default value is empty) + // Parameter name => description (default value is empty). 'callback' => '(string) An optional JSONP callback function.', ); - // Response format + /** + * Response format + * + * @var array + */ public $response_format = array(); - // Request format + /** + * Request format + * + * @var array + */ public $request_format = array(); - // Is this endpoint still in testing phase? If so, not available to the public. + /** + * Is this endpoint still in testing phase? If so, not available to the public. + * + * @var bool + */ public $in_testing = false; - // Is this endpoint still allowed if the site in question is flagged? + /** + * Is this endpoint still allowed if the site in question is flagged? + * + * @var bool + */ public $allowed_if_flagged = false; - // Is this endpoint allowed if the site is red flagged? + /** + * Is this endpoint allowed if the site is red flagged? + * + * @var bool + */ public $allowed_if_red_flagged = false; - // Is this endpoint allowed if the site is deleted? + /** + * Is this endpoint allowed if the site is deleted? + * + * @var bool + */ public $allowed_if_deleted = false; /** - * @var string Version of the API + * Version of the API + * + * @var string */ public $version = ''; /** - * @var string Example request to make + * Example request to make + * + * @var string */ public $example_request = ''; /** - * @var string Example request data (for POST methods) + * Example request data (for POST methods) + * + * @var string */ public $example_request_data = ''; /** - * @var string Example response from $example_request + * Example response from $example_request + * + * @var string */ public $example_response = ''; /** - * @var bool Set to true if the endpoint implements its own filtering instead of the standard `fields` query method + * Set to true if the endpoint implements its own filtering instead of the standard `fields` query method + * + * @var bool */ public $custom_fields_filtering = false; /** - * @var bool Set to true if the endpoint accepts all cross origin requests. You probably should not set this flag. + * Set to true if the endpoint accepts all cross origin requests. You probably should not set this flag. + * + * @var bool */ public $allow_cross_origin_request = false; /** - * @var bool Set to true if the endpoint can recieve unauthorized POST requests. + * Set to true if the endpoint can recieve unauthorized POST requests. + * + * @var bool */ public $allow_unauthorized_request = false; /** - * @var bool Set to true if the endpoint should accept site based (not user based) authentication. + * Set to true if the endpoint should accept site based (not user based) authentication. + * + * @var bool */ public $allow_jetpack_site_auth = false; /** - * @var bool Set to true if the endpoint should accept auth from an upload token. + * Set to true if the endpoint should accept auth from an upload token. + * + * @var bool */ public $allow_upload_token_auth = false; /** - * @var bool Set to true if the endpoint should require auth from a Rewind auth token. + * Set to true if the endpoint should require auth from a Rewind auth token. + * + * @var bool */ public $require_rewind_auth = false; @@ -139,7 +239,12 @@ abstract class WPCOM_JSON_API_Endpoint { */ public $allow_fallback_to_jetpack_blog_token = false; - function __construct( $args ) { + /** + * Constructor. + * + * @param string|array|object $args Args. + */ + public function __construct( $args ) { $defaults = array( 'in_testing' => false, 'allowed_if_flagged' => false, @@ -195,7 +300,7 @@ abstract class WPCOM_JSON_API_Endpoint { $this->deprecated = $args['deprecated']; $this->new_version = $args['new_version']; - // Ensure max version is not less than min version + // Ensure max version is not less than min version. if ( version_compare( $this->min_version, $this->max_version, '>' ) ) { $this->max_version = $this->min_version; } @@ -232,12 +337,12 @@ abstract class WPCOM_JSON_API_Endpoint { $this->query = array_filter( array_merge( $this->query, $args['query_parameters'] ) ); } - $this->api = WPCOM_JSON_API::init(); // Auto-add to WPCOM_JSON_API + $this->api = WPCOM_JSON_API::init(); // Auto-add to WPCOM_JSON_API. $this->links = WPCOM_JSON_API_Links::getInstance(); /** Example Request/Response */ - // Examples for endpoint documentation request + // Examples for endpoint documentation request. $this->example_request = $args['example_request']; $this->example_request_data = $args['example_request_data']; $this->example_response = $args['example_response']; @@ -245,8 +350,14 @@ abstract class WPCOM_JSON_API_Endpoint { $this->api->add( $this ); } - // Get all query args. Prefill with defaults - function query_args( $return_default_values = true, $cast_and_filter = true ) { + /** + * Get all query args. Prefill with defaults. + * + * @param bool $return_default_values Whether to include default values in the response. + * @param bool $cast_and_filter Whether to cast and filter input according to the documentation. + * @return array + */ + public function query_args( $return_default_values = true, $cast_and_filter = true ) { $args = array_intersect_key( $this->api->query, $this->query ); if ( ! $cast_and_filter ) { @@ -256,8 +367,14 @@ abstract class WPCOM_JSON_API_Endpoint { return $this->cast_and_filter( $args, $this->query, $return_default_values ); } - // Get POST body data - function input( $return_default_values = true, $cast_and_filter = true ) { + /** + * Get POST body data. + * + * @param bool $return_default_values Whether to include default values in the response. + * @param bool $cast_and_filter Whether to cast and filter input according to the documentation. + * @return mixed + */ + public function input( $return_default_values = true, $cast_and_filter = true ) { $input = trim( (string) $this->api->post_body ); $content_type = (string) $this->api->content_type; if ( $content_type ) { @@ -278,20 +395,21 @@ abstract class WPCOM_JSON_API_Endpoint { return null; } } else { - if ( is_null( $return ) && json_encode( null ) !== $input ) { + if ( $return === null && wp_json_encode( null ) !== $input ) { return null; } } break; case 'multipart/form-data': + // phpcs:ignore WordPress.Security.NonceVerification.Missing $return = array_merge( stripslashes_deep( $_POST ), $_FILES ); break; case 'application/x-www-form-urlencoded': - // attempt JSON first, since probably a curl command + // attempt JSON first, since probably a curl command. $return = json_decode( $input, true ); - if ( is_null( $return ) ) { + if ( $return === null ) { wp_parse_str( $input, $return ); } @@ -315,7 +433,12 @@ abstract class WPCOM_JSON_API_Endpoint { return $return; } - + /** + * Fetch a body via secure request. + * + * @param string $secure_key Key for the request. + * @return mixed|null API response, or null if the request failed. + */ protected function get_secure_body( $secure_key ) { $response = Client::wpcom_json_api_request_as_blog( sprintf( '/sites/%d/secure-request', Jetpack_Options::get_option( 'id' ) ), @@ -329,7 +452,16 @@ abstract class WPCOM_JSON_API_Endpoint { return json_decode( $response['body'], true ); } - function cast_and_filter( $data, $documentation, $return_default_values = false, $for_output = false ) { + /** + * Cast and filter data. + * + * @param mixed $data Data to cast and filter. + * @param array $documentation Documentation for keys in `$data` to keep and cast. + * @param bool $return_default_values Set default values from `$documentation` to process. + * @param bool $for_output See `$this->cast_and_filter_item()`. + * @return mixed Filtered data. + */ + public function cast_and_filter( $data, $documentation, $return_default_values = false, $for_output = false ) { $return_as_object = false; if ( is_object( $data ) ) { // @todo this should probably be a deep copy if $data can ever have nested objects @@ -346,21 +478,21 @@ abstract class WPCOM_JSON_API_Endpoint { foreach ( $documentation as $key => $description ) { if ( is_array( $description ) ) { - // String or boolean array keys only + // String or boolean array keys only. $whitelist = array_keys( $description ); if ( $whitelist === $boolean_arg || $whitelist === $naeloob_arg ) { - // Truthiness + // Truthiness. if ( isset( $data[ $key ] ) ) { $return[ $key ] = (bool) WPCOM_JSON_API::is_truthy( $data[ $key ] ); } elseif ( $return_default_values ) { $return[ $key ] = $whitelist === $naeloob_arg; // Default to true for naeloob_arg and false for boolean_arg. } } elseif ( isset( $data[ $key ] ) && isset( $description[ $data[ $key ] ] ) ) { - // String Key + // String Key. $return[ $key ] = (string) $data[ $key ]; } elseif ( $return_default_values ) { - // Default value + // Default value. $return[ $key ] = (string) current( $whitelist ); } @@ -370,7 +502,7 @@ abstract class WPCOM_JSON_API_Endpoint { $types = $this->parse_types( $description ); $type = array_shift( $types ); - // Explicit default - string and int only for now. Always set these reguardless of $return_default_values + // Explicit default - string and int only for now. Always set these reguardless of $return_default_values. if ( isset( $type['default'] ) ) { if ( ! isset( $data[ $key ] ) ) { $data[ $key ] = $type['default']; @@ -402,8 +534,15 @@ abstract class WPCOM_JSON_API_Endpoint { * object:category means a hash of categories * * Handles object typing - object>post means an object of type post + * + * @param array $return Array to assign the value into. + * @param string|array $type Type to cast. + * @param string|int $key Key in `$return` to assign the value to. + * @param mixed $value Value to cast. + * @param array $types Fallback types. + * @param bool $for_output Appears to affect formatting of 'date' types. */ - function cast_and_filter_item( &$return, $type, $key, $value, $types = array(), $for_output = false ) { + public function cast_and_filter_item( &$return, $type, $key, $value, $types = array(), $for_output = false ) { if ( is_string( $type ) ) { $type = compact( 'type' ); } @@ -423,7 +562,7 @@ abstract class WPCOM_JSON_API_Endpoint { $return[ $key ] = (string) esc_url_raw( $value ); break; case 'string': - // Fallback string -> array, or for string -> object + // Fallback string -> array, or for string -> object. if ( is_array( $value ) || is_object( $value ) ) { if ( ! empty( $types[0] ) ) { $next_type = array_shift( $types ); @@ -431,7 +570,7 @@ abstract class WPCOM_JSON_API_Endpoint { } } - // Fallback string -> false + // Fallback string -> false. if ( ! is_string( $value ) ) { if ( ! empty( $types[0] ) && 'false' === $types[0]['type'] ) { $next_type = array_shift( $types ); @@ -451,7 +590,7 @@ abstract class WPCOM_JSON_API_Endpoint { if ( is_array( $value ) ) { if ( isset( $value['name'] ) && is_array( $value['name'] ) ) { // It's a $_FILES array - // Reformat into array of $_FILES items + // Reformat into array of $_FILES items. $files = array(); foreach ( $value['name'] as $k => $v ) { @@ -464,12 +603,10 @@ abstract class WPCOM_JSON_API_Endpoint { $return[ $key ] = $files; break; } - } else { - // no break - treat as 'array' } - // nobreak + // no break - treat as 'array'. case 'array': - // Fallback array -> string + // Fallback array -> string. if ( is_string( $value ) ) { if ( ! empty( $types[0] ) ) { $next_type = array_shift( $types ); @@ -510,8 +647,8 @@ abstract class WPCOM_JSON_API_Endpoint { $return[ $key ] = (bool) WPCOM_JSON_API::is_truthy( $value ); break; case 'object': - // Fallback object -> false - if ( is_scalar( $value ) || is_null( $value ) ) { + // Fallback object -> false. + if ( is_scalar( $value ) || $value === null ) { if ( ! empty( $types[0] ) && 'false' === $types[0]['type'] ) { return $this->cast_and_filter_item( $return, 'false', $key, $value, $types, $for_output ); } @@ -768,10 +905,10 @@ abstract class WPCOM_JSON_API_Endpoint { break; case 'visibility': - // This is needed to fix a bug in WPAndroid where `public: "PUBLIC"` is sent in place of `public: 1` + // This is needed to fix a bug in WPAndroid where `public: "PUBLIC"` is sent in place of `public: 1`. if ( 'public' === strtolower( $value ) ) { $return[ $key ] = 1; - } else if ( 'private' === strtolower( $value ) ) { + } elseif ( 'private' === strtolower( $value ) ) { $return[ $key ] = -1; } else { $return[ $key ] = (int) $value; @@ -793,12 +930,19 @@ abstract class WPCOM_JSON_API_Endpoint { $for_output ); } else { + // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error, WordPress.Security.EscapeOutput.OutputNotEscaped trigger_error( "Unknown API casting type {$type['type']}", E_USER_WARNING ); } } } - function parse_types( $text ) { + /** + * Parse types from text. + * + * @param string $text Text. + * @return array Types. + */ + public function parse_types( $text ) { if ( ! preg_match( '#^\(([^)]+)\)#', ltrim( $text ), $matches ) ) { return 'none'; } @@ -828,16 +972,20 @@ abstract class WPCOM_JSON_API_Endpoint { /** * Checks if the endpoint is publicly displayable + * + * @return bool */ - function is_publicly_documentable() { + public function is_publicly_documentable() { return '__do_not_document' !== $this->group && true !== $this->in_testing; } /** * Auto generates documentation based on description, method, path, path_labels, and query parameters. * Echoes HTML. + * + * @param bool $show_description Whether to show the description. */ - function document( $show_description = true ) { + public function document( $show_description = true ) { global $wpdb; $original_post = isset( $GLOBALS['post'] ) ? $GLOBALS['post'] : 'unset'; unset( $GLOBALS['post'] ); @@ -915,11 +1063,11 @@ abstract class WPCOM_JSON_API_Endpoint { $param_label = strtolower( str_replace( ' ', '-', $label ) ); ?> -<section class="<?php echo $param_label; ?>"> +<section class="<?php echo esc_attr( $param_label ); ?>"> <h2 id="apidoc-<?php echo esc_attr( $doc_section_key ); ?>"><?php echo wp_kses_post( $label ); ?></h2> -<table class="api-doc api-doc-<?php echo $param_label; ?>-parameters api-doc-<?php echo strtolower( str_replace( ' ', '-', $doc['group'] ) ); ?>"> +<table class="api-doc api-doc-<?php echo esc_attr( $param_label ); ?>-parameters api-doc-<?php echo esc_attr( strtolower( str_replace( ' ', '-', $doc['group'] ) ) ); ?>"> <thead> <tr> @@ -952,11 +1100,19 @@ abstract class WPCOM_JSON_API_Endpoint { <?php if ( 'unset' !== $original_post ) { - $GLOBALS['post'] = $original_post; + $GLOBALS['post'] = $original_post; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited } } - function add_http_build_query_to_php_content_example( $matches ) { + /** + * `preg_replace_callback` callback to add http_build_query to php content example. + * + * @todo Is this used anywhere? + * + * @param array $matches Matches. + * @return string + */ + public function add_http_build_query_to_php_content_example( $matches ) { $trimmed_match = ltrim( $matches[0] ); $pad = substr( $matches[0], 0, -1 * strlen( $trimmed_match ) ); $pad = ltrim( $pad, ' ' ); @@ -967,8 +1123,10 @@ abstract class WPCOM_JSON_API_Endpoint { /** * Recursively generates the <dl>'s to document item descriptions. * Echoes HTML. + * + * @param string|array $item Post data to output, or an array of key => data mappings. */ - function generate_doc_description( $item ) { + public function generate_doc_description( $item ) { if ( is_array( $item ) ) : ?> @@ -992,7 +1150,7 @@ abstract class WPCOM_JSON_API_Endpoint { * Auto generates documentation based on description, method, path, path_labels, and query parameters. * Echoes HTML. */ - function generate_documentation() { + public function generate_documentation() { $format = str_replace( '%d', '%s', $this->path ); $path_labeled = $format; if ( ! empty( $this->path_labels ) ) { @@ -1033,7 +1191,7 @@ abstract class WPCOM_JSON_API_Endpoint { } if ( 'response_format' !== $_property ) { - // hack - don't show "(default)" in response format + // hack - don't show "(default)" in response format. reset( $description ); $description_key = key( $description ); $description[ $description_key ] = "(default) {$description[$description_key]}"; @@ -1043,7 +1201,7 @@ abstract class WPCOM_JSON_API_Endpoint { $type = array(); $default = ''; - if ( 'none' == $types ) { + if ( 'none' === $types ) { $types = array(); $types[]['type'] = 'none'; } @@ -1057,10 +1215,9 @@ abstract class WPCOM_JSON_API_Endpoint { } } } - $type = '(' . join( '|', $type ) . ')'; - $noop = ''; // skip an index in list below - list( $noop, $description ) = explode( ')', $description, 2 ); - $description = trim( $description ); + $type = '(' . join( '|', $type ) . ')'; + list( , $description ) = explode( ')', $description, 2 ); + $description = trim( $description ); if ( $default ) { $description .= " Default: $default."; } @@ -1079,7 +1236,13 @@ abstract class WPCOM_JSON_API_Endpoint { return $doc; } - function user_can_view_post( $post_id ) { + /** + * Can the user view the post? + * + * @param int $post_id Post ID. + * @return bool|WP_Error + */ + public function user_can_view_post( $post_id ) { $post = get_post( $post_id ); if ( ! $post || is_wp_error( $post ) ) { return false; @@ -1102,12 +1265,12 @@ abstract class WPCOM_JSON_API_Endpoint { if ( ! current_user_can( 'read_post', $post->ID ) ) { return new WP_Error( 'unauthorized', 'User cannot view post', 403 ); } - } elseif ( in_array( $post->post_status, array( 'inherit', 'trash' ) ) ) { + } elseif ( in_array( $post->post_status, array( 'inherit', 'trash' ), true ) ) { if ( ! current_user_can( 'edit_post', $post->ID ) ) { return new WP_Error( 'unauthorized', 'User cannot view post', 403 ); } - } elseif ( 'auto-draft' === $post->post_status ) { - // allow auto-drafts + } elseif ( 'auto-draft' === $post->post_status ) { // phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedElseif + // allow auto-drafts. } else { return new WP_Error( 'unauthorized', 'User cannot view post', 403 ); } @@ -1117,7 +1280,7 @@ abstract class WPCOM_JSON_API_Endpoint { } if ( - -1 == get_option( 'blog_public' ) && + -1 === (int) get_option( 'blog_public' ) && /** * Filter access to a specific post. * @@ -1161,12 +1324,12 @@ abstract class WPCOM_JSON_API_Endpoint { /** * Returns author object. * - * @param object $author user ID, user row, WP_User object, comment row, post row - * @param bool $show_email_and_ip output the author's email address and IP address? + * @param object $author user ID, user row, WP_User object, comment row, post row. + * @param bool $show_email_and_ip output the author's email address and IP address?. * * @return object */ - function get_author( $author, $show_email_and_ip = false ) { + public function get_author( $author, $show_email_and_ip = false ) { $ip_address = isset( $author->comment_author_IP ) ? $author->comment_author_IP : ''; if ( isset( $author->comment_author_email ) ) { @@ -1176,15 +1339,15 @@ abstract class WPCOM_JSON_API_Endpoint { $name = $author->comment_author; $first_name = ''; $last_name = ''; - $URL = $author->comment_author_url; - $avatar_URL = $this->api->get_avatar_url( $author ); - $profile_URL = 'https://en.gravatar.com/' . md5( strtolower( trim( $email ) ) ); + $url = $author->comment_author_url; + $avatar_url = $this->api->get_avatar_url( $author ); + $profile_url = 'https://en.gravatar.com/' . md5( strtolower( trim( $email ) ) ); $nice = ''; $site_id = -1; // Comment author URLs and Emails are sent through wp_kses() on save, which replaces "&" with "&" - // "&" is the only email/URL character altered by wp_kses() - foreach ( array( 'email', 'URL' ) as $field ) { + // "&" is the only email/URL character altered by wp_kses(). + foreach ( array( 'email', 'url' ) as $field ) { $$field = str_replace( '&', '&', $$field ); } } else { @@ -1194,7 +1357,7 @@ abstract class WPCOM_JSON_API_Endpoint { $author = $author->ID; } elseif ( isset( $author->post_author ) ) { // then $author is a Post Object. - if ( 0 == $author->post_author ) { + if ( ! $author->post_author ) { return null; } /** @@ -1216,7 +1379,7 @@ abstract class WPCOM_JSON_API_Endpoint { $name = get_post_meta( $post_id, '_jetpack_author', true ); $first_name = ''; $last_name = ''; - $URL = ''; + $url = ''; $nice = ''; } else { $author = $author->post_author; @@ -1226,7 +1389,7 @@ abstract class WPCOM_JSON_API_Endpoint { if ( ! isset( $id ) ) { $user = get_user_by( 'id', $author ); if ( ! $user || is_wp_error( $user ) ) { - trigger_error( 'Unknown user', E_USER_WARNING ); + trigger_error( 'Unknown user', E_USER_WARNING ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error return null; } @@ -1236,7 +1399,7 @@ abstract class WPCOM_JSON_API_Endpoint { $name = $user->display_name; $first_name = $user->first_name; $last_name = $user->last_name; - $URL = $user->user_url; + $url = $user->user_url; $nice = $user->user_nicename; } if ( defined( 'IS_WPCOM' ) && IS_WPCOM && ! $is_jetpack ) { @@ -1244,17 +1407,17 @@ abstract class WPCOM_JSON_API_Endpoint { $site_id = $active_blog->blog_id; if ( $site_id > -1 ) { $site_visible = ( - -1 != $active_blog->public || + -1 !== (int) $active_blog->public || is_private_blog_user( $site_id, get_current_user_id() ) ); } - $profile_URL = "https://en.gravatar.com/{$login}"; + $profile_url = "https://en.gravatar.com/{$login}"; } else { - $profile_URL = 'https://en.gravatar.com/' . md5( strtolower( trim( $email ) ) ); + $profile_url = 'https://en.gravatar.com/' . md5( strtolower( trim( $email ) ) ); $site_id = -1; } - $avatar_URL = $this->api->get_avatar_url( $email ); + $avatar_url = $this->api->get_avatar_url( $email ); } if ( $show_email_and_ip ) { @@ -1268,15 +1431,15 @@ abstract class WPCOM_JSON_API_Endpoint { $author = array( 'ID' => (int) $id, 'login' => (string) $login, - 'email' => $email, // (string|bool) + 'email' => $email, // string|bool. 'name' => (string) $name, 'first_name' => (string) $first_name, 'last_name' => (string) $last_name, 'nice_name' => (string) $nice, - 'URL' => (string) esc_url_raw( $URL ), - 'avatar_URL' => (string) esc_url_raw( $avatar_URL ), - 'profile_URL' => (string) esc_url_raw( $profile_URL ), - 'ip_address' => $ip_address, // (string|bool) + 'URL' => (string) esc_url_raw( $url ), + 'avatar_URL' => (string) esc_url_raw( $avatar_url ), + 'profile_URL' => (string) esc_url_raw( $profile_url ), + 'ip_address' => $ip_address, // string|bool. ); if ( $site_id > -1 ) { @@ -1287,7 +1450,13 @@ abstract class WPCOM_JSON_API_Endpoint { return (object) $author; } - function get_media_item( $media_id ) { + /** + * Get a media item. + * + * @param int $media_id Media post ID. + * @return object|WP_Error Media item data, or WP_Error. + */ + public function get_media_item( $media_id ) { $media_item = get_post( $media_id ); if ( ! $media_item || is_wp_error( $media_item ) ) { @@ -1322,7 +1491,15 @@ abstract class WPCOM_JSON_API_Endpoint { return (object) $response; } - function get_media_item_v1_1( $media_id, $media_item = null, $file = null ) { + /** + * Get a v1.1 media item. + * + * @param int $media_id Media post ID. + * @param WP_Post|null $media_item Media item. + * @param string|null $file File path. + * @return object|WP_Error Media item data, or WP_Error. + */ + public function get_media_item_v1_1( $media_id, $media_item = null, $file = null ) { if ( ! $media_item ) { $media_item = get_post( $media_id ); @@ -1345,7 +1522,10 @@ abstract class WPCOM_JSON_API_Endpoint { ? $attachment_metadata['filesize'] : 0; } else { - $filesize = filesize( $attachment_file ); + // For VideoPress videos, $attachment_file is the video URL. + $filesize = file_exists( $attachment_file ) + ? filesize( $attachment_file ) + : 0; } $response = array( @@ -1408,7 +1588,7 @@ abstract class WPCOM_JSON_API_Endpoint { } } - if ( in_array( $ext, array( 'mp3', 'm4a', 'wav', 'ogg' ) ) ) { + if ( in_array( $ext, array( 'mp3', 'm4a', 'wav', 'ogg' ), true ) ) { $metadata = wp_get_attachment_metadata( $media_item->ID ); $response['length'] = $metadata['length']; $response['exif'] = $metadata; @@ -1417,9 +1597,8 @@ abstract class WPCOM_JSON_API_Endpoint { $is_video = false; if ( - in_array( $ext, array( 'ogv', 'mp4', 'mov', 'wmv', 'avi', 'mpg', '3gp', '3g2', 'm4v' ) ) - || - $response['mime_type'] === 'video/videopress' + in_array( $ext, array( 'ogv', 'mp4', 'mov', 'wmv', 'avi', 'mpg', '3gp', '3g2', 'm4v' ), true ) + || 'video/videopress' === $response['mime_type'] ) { $is_video = true; } @@ -1436,7 +1615,7 @@ abstract class WPCOM_JSON_API_Endpoint { $response['length'] = $metadata['length']; } - // add VideoPress info + // add VideoPress info. if ( function_exists( 'video_get_info_by_blogpostid' ) ) { $info = video_get_info_by_blogpostid( $this->api->get_blog_id_for_output(), $media_item->ID ); @@ -1465,7 +1644,19 @@ abstract class WPCOM_JSON_API_Endpoint { $response['allow_download'] = (string) (int) $metadata['videopress']['allow_download']; } - // Thumbnails + if ( isset( $info->thumbnail_generating ) ) { + $response['thumbnail_generating'] = (bool) intval( $info->thumbnail_generating ); + } elseif ( isset( $metadata['videopress']['thumbnail_generating'] ) ) { + $response['thumbnail_generating'] = (bool) intval( $metadata['videopress']['thumbnail_generating'] ); + } + + if ( isset( $info->privacy_setting ) ) { + $response['privacy_setting'] = (int) $info->privacy_setting; + } elseif ( isset( $metadata['videopress']['privacy_setting'] ) ) { + $response['privacy_setting'] = (int) $metadata['videopress']['privacy_setting']; + } + + // Thumbnails. if ( function_exists( 'video_format_done' ) && function_exists( 'video_image_url_by_guid' ) ) { $response['thumbnails'] = array( 'fmt_hd' => '', @@ -1503,7 +1694,7 @@ abstract class WPCOM_JSON_API_Endpoint { ), ); - // add VideoPress link to the meta + // add VideoPress link to the meta. if ( isset( $response['videopress_guid'] ) ) { if ( function_exists( 'video_get_info_by_blogpostid' ) ) { $response['meta']->links->videopress = (string) $this->links->get_link( '/videos/%s', $response['videopress_guid'], '' ); @@ -1517,10 +1708,18 @@ abstract class WPCOM_JSON_API_Endpoint { return (object) $response; } - function get_taxonomy( $taxonomy_id, $taxonomy_type, $context ) { + /** + * Get a formatted taxonomy. + * + * @param int $taxonomy_id Taxonomy ID. + * @param string $taxonomy_type Name of taxonomy. + * @param string $context Context, 'edit' or 'display'. + * @return object|WP_Error + */ + public function get_taxonomy( $taxonomy_id, $taxonomy_type, $context ) { $taxonomy = get_term_by( 'slug', $taxonomy_id, $taxonomy_type ); - // keep updating this function + // keep updating this function. if ( ! $taxonomy || is_wp_error( $taxonomy ) ) { return new WP_Error( 'unknown_taxonomy', 'Unknown taxonomy', 404 ); } @@ -1528,8 +1727,16 @@ abstract class WPCOM_JSON_API_Endpoint { return $this->format_taxonomy( $taxonomy, $taxonomy_type, $context ); } - function format_taxonomy( $taxonomy, $taxonomy_type, $context ) { - // Permissions + /** + * Format a taxonomy. + * + * @param WP_Term $taxonomy Taxonomy. + * @param string $taxonomy_type Name of taxonomy. + * @param string $context Context, 'edit' or 'display'. + * @return object|WP_Error + */ + public function format_taxonomy( $taxonomy, $taxonomy_type, $context ) { + // Permissions. switch ( $context ) { case 'edit': $tax = get_taxonomy( $taxonomy_type ); @@ -1538,7 +1745,7 @@ abstract class WPCOM_JSON_API_Endpoint { } break; case 'display': - if ( -1 == get_option( 'blog_public' ) && ! current_user_can( 'read' ) ) { + if ( -1 === (int) get_option( 'blog_public' ) && ! current_user_can( 'read' ) ) { return new WP_Error( 'unauthorized', 'User cannot view taxonomy', 403 ); } break; @@ -1572,12 +1779,11 @@ abstract class WPCOM_JSON_API_Endpoint { /** * Returns ISO 8601 formatted datetime: 2011-12-08T01:15:36-08:00 * - * @param $date_gmt (string) GMT datetime string. - * @param $date (string) Optional. Used to calculate the offset from GMT. - * + * @param string $date_gmt GMT datetime string. + * @param string $date Optional. Used to calculate the offset from GMT. * @return string */ - function format_date( $date_gmt, $date = null ) { + public function format_date( $date_gmt, $date = null ) { return WPCOM_JSON_API_Date::format_date( $date_gmt, $date ); } @@ -1624,23 +1830,33 @@ abstract class WPCOM_JSON_API_Endpoint { ); } - // Load the functions.php file for the current theme to get its post formats, CPTs, etc. - function load_theme_functions() { + /** + * Load the functions.php file for the current theme to get its post formats, CPTs, etc. + */ + public function load_theme_functions() { if ( false === defined( 'STYLESHEETPATH' ) ) { wp_templating_constants(); } - // bail if we've done this already (can happen when calling /batch endpoint) + // bail if we've done this already (can happen when calling /batch endpoint). if ( defined( 'REST_API_THEME_FUNCTIONS_LOADED' ) ) { return; } // VIP context loading is handled elsewhere, so bail to prevent - // duplicate loading. See `switch_to_blog_and_validate_user()` + // duplicate loading. See `switch_to_blog_and_validate_user()`. if ( defined( 'WPCOM_IS_VIP_ENV' ) && WPCOM_IS_VIP_ENV ) { return; } + $do_check_theme = + defined( 'REST_API_TEST_REQUEST' ) && REST_API_TEST_REQUEST || + defined( 'IS_WPCOM' ) && IS_WPCOM; + + if ( $do_check_theme && ! wpcom_should_load_theme_files_on_rest_api() ) { + return; + } + define( 'REST_API_THEME_FUNCTIONS_LOADED', true ); // the theme info we care about is found either within functions.php or one of the jetpack files. @@ -1664,13 +1880,13 @@ abstract class WPCOM_JSON_API_Endpoint { } } - // add inc/wpcom.php and/or includes/wpcom.php + // add inc/wpcom.php and/or includes/wpcom.php. wpcom_load_theme_compat_file(); - // Enable including additional directories or files in actions to be copied + // Enable including additional directories or files in actions to be copied. $copy_dirs = apply_filters( 'restapi_theme_action_copy_dirs', $copy_dirs ); - // since the stuff we care about (CPTS, post formats, are usually on setup or init hooks, we want to load those) + // since the stuff we care about (CPTS, post formats, are usually on setup or init hooks, we want to load those). $this->copy_hooks( 'after_setup_theme', 'restapi_theme_after_setup_theme', $copy_dirs ); /** @@ -1703,11 +1919,18 @@ abstract class WPCOM_JSON_API_Endpoint { do_action( 'restapi_theme_init' ); } - function copy_hooks( $from_hook, $to_hook, $base_paths ) { + /** + * Copy hook functions. + * + * @param string $from_hook Hook to copy from. + * @param string $to_hook Hook to copy to. + * @param array $base_paths Only copy hooks defined in the specified paths. + */ + public function copy_hooks( $from_hook, $to_hook, $base_paths ) { global $wp_filter; foreach ( $wp_filter as $hook => $actions ) { - if ( $from_hook != $hook ) { + if ( $from_hook !== $hook ) { continue; } if ( ! has_action( $hook ) ) { @@ -1715,17 +1938,17 @@ abstract class WPCOM_JSON_API_Endpoint { } foreach ( $actions as $priority => $callbacks ) { - foreach ( $callbacks as $callback_key => $callback_data ) { + foreach ( $callbacks as $callback_data ) { $callback = $callback_data['function']; - // use reflection api to determine filename where function is defined + // use reflection api to determine filename where function is defined. $reflection = $this->get_reflection( $callback ); if ( false !== $reflection ) { $file_name = $reflection->getFileName(); foreach ( $base_paths as $base_path ) { - // only copy hooks with functions which are part of the specified files + // only copy hooks with functions which are part of the specified files. if ( 0 === strpos( $file_name, $base_path ) ) { add_action( $to_hook, @@ -1741,7 +1964,13 @@ abstract class WPCOM_JSON_API_Endpoint { } } - function get_reflection( $callback ) { + /** + * Get a ReflectionMethod or ReflectionFunction for the callback. + * + * @param callable $callback Callback. + * @return ReflectionMethod|ReflectionFunction|false + */ + public function get_reflection( $callback ) { if ( is_array( $callback ) ) { list( $class, $method ) = $callback; return new ReflectionMethod( $class, $method ); @@ -1752,11 +1981,11 @@ abstract class WPCOM_JSON_API_Endpoint { return new ReflectionMethod( $class, $method ); } - if ( method_exists( $callback, "__invoke" ) ) { - return new ReflectionMethod( $callback, "__invoke" ); + if ( method_exists( $callback, '__invoke' ) ) { + return new ReflectionMethod( $callback, '__invoke' ); } - if ( is_string( $callback ) && strpos( $callback, '::' ) == false && function_exists( $callback ) ) { + if ( is_string( $callback ) && strpos( $callback, '::' ) === false && function_exists( $callback ) ) { return new ReflectionFunction( $callback ); } @@ -1764,13 +1993,13 @@ abstract class WPCOM_JSON_API_Endpoint { } /** - * Check whether a user can view or edit a post type + * Check whether a user can view or edit a post type. * - * @param string $post_type post type to check - * @param string $context 'display' or 'edit' + * @param string $post_type post type to check. + * @param string $context 'display' or 'edit'. * @return bool */ - function current_user_can_access_post_type( $post_type, $context = 'display' ) { + public function current_user_can_access_post_type( $post_type, $context = 'display' ) { $post_type_object = get_post_type_object( $post_type ); if ( ! $post_type_object ) { return false; @@ -1786,23 +2015,30 @@ abstract class WPCOM_JSON_API_Endpoint { } } - function is_post_type_allowed( $post_type ) { - // if the post type is empty, that's fine, WordPress will default to post + /** + * Is the post type allowed? + * + * @param string $post_type Post type. + * @return bool + */ + public function is_post_type_allowed( $post_type ) { + // if the post type is empty, that's fine, WordPress will default to post. if ( empty( $post_type ) ) { return true; } - // allow special 'any' type - if ( 'any' == $post_type ) { + // allow special 'any' type. + if ( 'any' === $post_type ) { return true; } - // check for allowed types - if ( in_array( $post_type, $this->_get_whitelisted_post_types() ) ) { + // check for allowed types. + if ( in_array( $post_type, $this->_get_whitelisted_post_types(), true ) ) { return true; } - if ( $post_type_object = get_post_type_object( $post_type ) ) { + $post_type_object = get_post_type_object( $post_type ); + if ( $post_type_object ) { if ( ! empty( $post_type_object->show_in_rest ) ) { return $post_type_object->show_in_rest; } @@ -1819,7 +2055,7 @@ abstract class WPCOM_JSON_API_Endpoint { * * @return array Whitelisted post types. */ - protected function _get_whitelisted_post_types() { + protected function _get_whitelisted_post_types() { // phpcs:ignore PSR2.Methods.MethodDeclaration.Underscore -- Legacy. $allowed_types = array( 'post', 'page', 'revision' ); /** @@ -1836,30 +2072,105 @@ abstract class WPCOM_JSON_API_Endpoint { return array_unique( $allowed_types ); } - function handle_media_creation_v1_1( $media_files, $media_urls, $media_attrs = array(), $force_parent_id = false ) { + /** + * Mobile apps are allowed free video uploads, but limited to 5 minutes in length. + * + * @param array $media_item the media item to evaluate. + * + * @return bool true if the media item is a video that was uploaded via the mobile + * app that is longer than 5 minutes. + */ + public function media_item_is_free_video_mobile_upload_and_too_long( $media_item ) { + if ( ! $media_item ) { + return false; + } + + // Verify file is a video. + $is_video = preg_match( '@^video/@', $media_item['type'] ); + if ( ! $is_video ) { + return false; + } + + // Check if the request is from a mobile app, where we allow free video uploads at limited length. + if ( ! in_array( $this->api->token_details['client_id'], VIDEOPRESS_ALLOWED_REST_API_CLIENT_IDS, true ) ) { + return false; + } + + // We're only worried about free sites. + require_once WP_CONTENT_DIR . '/admin-plugins/wpcom-billing.php'; + $current_plan = WPCOM_Store_API::get_current_plan( get_current_blog_id() ); + if ( ! $current_plan['is_free'] ) { + return false; + } + + // Check if video is longer than 5 minutes. + $video_meta = wp_read_video_metadata( $media_item['tmp_name'] ); + if ( + false !== $video_meta && + isset( $video_meta['length'] ) && + 5 * MINUTE_IN_SECONDS < $video_meta['length'] + ) { + videopress_log( + 'videopress_app_upload_length_block', + 'Mobile app upload on free site blocked because length was longer than 5 minutes.', + null, + null, + null, + null, + array( + 'blog_id' => get_current_blog_id(), + 'user_id' => get_current_user_id(), + ) + ); + return true; + } + + return false; + } + + /** + * Handle a v1.1 media creation. + * + * Only one of $media_files and $media_urls should be non-empty. + * + * @param array $media_files File upload data. + * @param array $media_urls URLs to fetch. + * @param array $media_attrs Attributes corresponding to each entry in `$media_files`/`$media_urls`. + * @param int|false $force_parent_id Force the parent ID, overriding `$media_attrs[]['parent_id']`. + * @return array Two items: + * - media_ids: IDs created, by index in `$media_files`/`$media_urls`. + * - errors: Errors encountered, by index in `$media_files`/`$media_urls`. + */ + public function handle_media_creation_v1_1( $media_files, $media_urls, $media_attrs = array(), $force_parent_id = false ) { add_filter( 'upload_mimes', array( $this, 'allow_video_uploads' ) ); - $media_ids = $errors = array(); + $media_ids = array(); + $errors = array(); $user_can_upload_files = current_user_can( 'upload_files' ) || $this->api->is_authorized_with_upload_token(); - $media_attrs = array_values( $media_attrs ); // reset the keys + $media_attrs = array_values( $media_attrs ); // reset the keys. $i = 0; if ( ! empty( $media_files ) ) { $this->api->trap_wp_die( 'upload_error' ); foreach ( $media_files as $media_item ) { $_FILES['.api.media.item.'] = $media_item; + if ( ! $user_can_upload_files ) { $media_id = new WP_Error( 'unauthorized', 'User cannot upload media.', 403 ); } else { - if ( $force_parent_id ) { - $parent_id = absint( $force_parent_id ); - } elseif ( ! empty( $media_attrs[ $i ] ) && ! empty( $media_attrs[ $i ]['parent_id'] ) ) { - $parent_id = absint( $media_attrs[ $i ]['parent_id'] ); + if ( $this->media_item_is_free_video_mobile_upload_and_too_long( $media_item ) ) { + $media_id = new WP_Error( 'upload_video_length', 'Video uploads longer than 5 minutes require a paid plan.', 400 ); } else { - $parent_id = 0; + if ( $force_parent_id ) { + $parent_id = absint( $force_parent_id ); + } elseif ( ! empty( $media_attrs[ $i ] ) && ! empty( $media_attrs[ $i ]['parent_id'] ) ) { + $parent_id = absint( $media_attrs[ $i ]['parent_id'] ); + } else { + $parent_id = 0; + } + $media_id = media_handle_upload( '.api.media.item.', $parent_id ); } - $media_id = media_handle_upload( '.api.media.item.', $parent_id ); } if ( is_wp_error( $media_id ) ) { $errors[ $i ]['file'] = $media_item['name']; @@ -1912,7 +2223,7 @@ abstract class WPCOM_JSON_API_Endpoint { $attrs = $media_attrs[ $index ]; $insert = array(); - // Attributes: Title, Caption, Description + // Attributes: Title, Caption, Description. if ( isset( $attrs['title'] ) ) { $insert['post_title'] = $attrs['title']; @@ -1931,14 +2242,14 @@ abstract class WPCOM_JSON_API_Endpoint { wp_update_post( (object) $insert ); } - // Attributes: Alt + // Attributes: Alt. if ( isset( $attrs['alt'] ) ) { $alt = wp_strip_all_tags( $attrs['alt'], true ); update_post_meta( $media_id, '_wp_attachment_image_alt', $alt ); } - // Attributes: Artist, Album + // Attributes: Artist, Album. $id3_meta = array(); @@ -1949,7 +2260,7 @@ abstract class WPCOM_JSON_API_Endpoint { } if ( ! empty( $id3_meta ) ) { - // Before updating metadata, ensure that the item is audio + // Before updating metadata, ensure that the item is audio. $item = $this->get_media_item_v1_1( $media_id ); if ( 0 === strpos( $item->mime_type, 'audio/' ) ) { wp_update_attachment_metadata( $media_id, $id3_meta ); @@ -1965,12 +2276,20 @@ abstract class WPCOM_JSON_API_Endpoint { } - function handle_media_sideload( $url, $parent_post_id = 0, $type = 'any' ) { + /** + * Handle a media sideload. + * + * @param string $url URL. + * @param int $parent_post_id Parent post ID. + * @param string $type Type. + * @return int|WP_Error|false Media post ID, or error, or false if nothing was sideloaded. + */ + public function handle_media_sideload( $url, $parent_post_id = 0, $type = 'any' ) { if ( ! function_exists( 'download_url' ) || ! function_exists( 'media_handle_sideload' ) ) { return false; } - // if we didn't get a URL, let's bail + // if we didn't get a URL, let's bail. $parsed = wp_parse_url( $url ); if ( empty( $parsed ) ) { return false; @@ -1984,11 +2303,11 @@ abstract class WPCOM_JSON_API_Endpoint { // First check to see if we get a mime-type match by file, otherwise, check to // see if WordPress supports this file as an image. If neither, then it is not supported. if ( ! $this->is_file_supported_for_sideloading( $tmp ) || 'image' === $type && ! file_is_displayable_image( $tmp ) ) { - @unlink( $tmp ); + @unlink( $tmp ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged return new WP_Error( 'invalid_input', 'Invalid file type.', 403 ); } - // emulate a $_FILES entry + // emulate a $_FILES entry. $file_array = array( 'name' => basename( wp_parse_url( $url, PHP_URL_PATH ) ), 'tmp_name' => $tmp, @@ -1996,7 +2315,7 @@ abstract class WPCOM_JSON_API_Endpoint { $id = media_handle_sideload( $file_array, $parent_post_id ); if ( file_exists( $tmp ) ) { - @unlink( $tmp ); + @unlink( $tmp ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged } if ( is_wp_error( $id ) ) { @@ -2021,23 +2340,29 @@ abstract class WPCOM_JSON_API_Endpoint { return jetpack_is_file_supported_for_sideloading( $file ); } - function allow_video_uploads( $mimes ) { - // if we are on Jetpack, bail - Videos are already allowed + /** + * Filter for `upload_mimes`. + * + * @param array $mimes Allowed mime types. + * @return array Allowed mime types. + */ + public function allow_video_uploads( $mimes ) { + // if we are on Jetpack, bail - Videos are already allowed. if ( ! defined( 'IS_WPCOM' ) || ! IS_WPCOM ) { return $mimes; } - // extra check that this filter is only ever applied during REST API requests + // extra check that this filter is only ever applied during REST API requests. if ( ! defined( 'REST_API_REQUEST' ) || ! REST_API_REQUEST ) { return $mimes; } // bail early if they already have the upgrade.. - if ( get_option( 'video_upgrade' ) == '1' ) { + if ( wpcom_site_has_videopress() ) { return $mimes; } - // lets whitelist to only specific clients right now + // lets whitelist to only specific clients right now. $clients_allowed_video_uploads = array(); /** * Filter the list of whitelisted video clients. @@ -2049,7 +2374,7 @@ abstract class WPCOM_JSON_API_Endpoint { * @param array $clients_allowed_video_uploads Array of whitelisted Video clients. */ $clients_allowed_video_uploads = apply_filters( 'rest_api_clients_allowed_video_uploads', $clients_allowed_video_uploads ); - if ( ! in_array( $this->api->token_details['client_id'], $clients_allowed_video_uploads ) ) { + if ( ! in_array( $this->api->token_details['client_id'], $clients_allowed_video_uploads ) ) { // phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict -- Check what types are expected here. return $mimes; } @@ -2071,7 +2396,7 @@ abstract class WPCOM_JSON_API_Endpoint { if ( ! empty( $video_exts ) ) { foreach ( $video_exts as $ext ) { foreach ( $mime_list as $ext_pattern => $mime ) { - if ( $ext != '' && strpos( $ext_pattern, $ext ) !== false ) { + if ( '' !== $ext && strpos( $ext_pattern, $ext ) !== false ) { $video_mimes[ $ext_pattern ] = $mime; } } @@ -2083,7 +2408,12 @@ abstract class WPCOM_JSON_API_Endpoint { return $mimes; } - function is_current_site_multi_user() { + /** + * Is the current site multi-user? + * + * @return bool + */ + public function is_current_site_multi_user() { $users = wp_cache_get( 'site_user_count', 'WPCOM_JSON_API_Endpoint' ); if ( false === $users ) { $user_query = new WP_User_Query( @@ -2098,12 +2428,24 @@ abstract class WPCOM_JSON_API_Endpoint { return $users > 1; } - function allows_cross_origin_requests() { - return 'GET' == $this->method || $this->allow_cross_origin_request; + /** + * Whether cross-origin requests are allowed. + * + * @return bool + */ + public function allows_cross_origin_requests() { + return 'GET' === $this->method || $this->allow_cross_origin_request; } - function allows_unauthorized_requests( $origin, $complete_access_origins ) { - return 'GET' == $this->method || ( $this->allow_unauthorized_request && in_array( $origin, $complete_access_origins ) ); + /** + * Whether unauthorized requests are allowed. + * + * @param string $origin Origin. + * @param string[] $complete_access_origins Access origins. + * @return bool + */ + public function allows_unauthorized_requests( $origin, $complete_access_origins ) { + return 'GET' === $this->method || ( $this->allow_unauthorized_request && in_array( $origin, $complete_access_origins, true ) ); } /** @@ -2119,7 +2461,12 @@ abstract class WPCOM_JSON_API_Endpoint { $this->api->is_jetpack_authorized_for_site(); } - function get_platform() { + /** + * Get platform. + * + * @return WPORG_Platform + */ + public function get_platform() { return wpcom_get_sal_platform( $this->api->token_details ); } @@ -2129,10 +2476,10 @@ abstract class WPCOM_JSON_API_Endpoint { * * Override this method if you want to do something different. * - * @param int $blog_id + * @param int $blog_id Blog ID. * @return bool */ - function force_wpcom_request( $blog_id ) { + public function force_wpcom_request( $blog_id ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable return false; } @@ -2143,7 +2490,7 @@ abstract class WPCOM_JSON_API_Endpoint { * @return array */ public function get_amp_cache_origins( $siteurl ) { - $host = parse_url( $siteurl, PHP_URL_HOST ); + $host = wp_parse_url( $siteurl, PHP_URL_HOST ); /* * From AMP docs: @@ -2182,7 +2529,6 @@ abstract class WPCOM_JSON_API_Endpoint { */ abstract public function callback( $path = '' ); - } -require_once dirname( __FILE__ ) . '/json-endpoints.php'; +require_once __DIR__ . '/json-endpoints.php'; |