REST API: Improve translations, comments, and readability in URL Details endpoint.

Improvements:
* Removes HTML tags from translatable strings. Uses `sprintf` with placeholder and translators comment.
* Spells out "OG" to "Open Graph" to help translators.
* Adds `@since` param to new filters.
* Improves comments for code standards and consistency.
* Improves readability by making multiple args multiline.
* Micro-optimizations to avoid unnecessary variable assignments.

Follow-up to [51973].

Props hellofromTonya, sergeybiryukov, swissspidy.
Fixes #54358.
Built from https://develop.svn.wordpress.org/trunk@52008


git-svn-id: http://core.svn.wordpress.org/trunk@51599 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
hellofromTonya 2021-11-04 12:44:01 +00:00
parent 42769ea145
commit 27d239d01b
2 changed files with 82 additions and 44 deletions

View File

@ -69,32 +69,49 @@ class WP_REST_URL_Details_Controller extends WP_REST_Controller {
return $this->add_additional_fields_schema( $this->schema ); return $this->add_additional_fields_schema( $this->schema );
} }
$schema = array( $this->schema = array(
'$schema' => 'http://json-schema.org/draft-04/schema#', '$schema' => 'http://json-schema.org/draft-04/schema#',
'title' => 'url-details', 'title' => 'url-details',
'type' => 'object', 'type' => 'object',
'properties' => array( 'properties' => array(
'title' => array( 'title' => array(
'description' => __( 'The contents of the <title> element from the URL.' ), 'description' => sprintf(
/* translators: %s: HTML title tag. */
__( 'The contents of the %s element from the URL.' ),
'<title>'
),
'type' => 'string', 'type' => 'string',
'context' => array( 'view', 'edit', 'embed' ), 'context' => array( 'view', 'edit', 'embed' ),
'readonly' => true, 'readonly' => true,
), ),
'icon' => array( 'icon' => array(
'description' => __( 'The favicon image link of the <link rel="icon"> element from the URL.' ), 'description' => sprintf(
/* translators: %s: HTML link tag. */
__( 'The favicon image link of the %s element from the URL.' ),
'<link rel="icon">'
),
'type' => 'string', 'type' => 'string',
'format' => 'uri', 'format' => 'uri',
'context' => array( 'view', 'edit', 'embed' ), 'context' => array( 'view', 'edit', 'embed' ),
'readonly' => true, 'readonly' => true,
), ),
'description' => array( 'description' => array(
'description' => __( 'The content of the <meta name="description"> element from the URL.' ), 'description' => sprintf(
/* translators: %s: HTML meta tag. */
__( 'The content of the %s element from the URL.' ),
'<meta name="description">'
),
'type' => 'string', 'type' => 'string',
'context' => array( 'view', 'edit', 'embed' ), 'context' => array( 'view', 'edit', 'embed' ),
'readonly' => true, 'readonly' => true,
), ),
'image' => array( 'image' => array(
'description' => __( 'The OG image link of the <meta property="og:image"> or <meta property="og:image:url"> element from the URL.' ), 'description' => sprintf(
/* translators: 1: HTML meta tag, 2: HTML meta tag. */
__( 'The Open Graph image link of the %1$s or %2$s element from the URL.' ),
'<meta property="og:image">',
'<meta property="og:image:url">'
),
'type' => 'string', 'type' => 'string',
'format' => 'uri', 'format' => 'uri',
'context' => array( 'view', 'edit', 'embed' ), 'context' => array( 'view', 'edit', 'embed' ),
@ -103,18 +120,16 @@ class WP_REST_URL_Details_Controller extends WP_REST_Controller {
), ),
); );
$this->schema = $schema;
return $this->add_additional_fields_schema( $this->schema ); return $this->add_additional_fields_schema( $this->schema );
} }
/** /**
* Retrieves the contents of the <title> tag from the HTML response. * Retrieves the contents of the `<title>` tag from the HTML response.
* *
* @since 5.9.0 * @since 5.9.0
* *
* @param WP_REST_REQUEST $request Full details about the request. * @param WP_REST_REQUEST $request Full details about the request.
* @return WP_REST_Response|WP_Error The parsed details as a response object, or an error. * @return WP_REST_Response|WP_Error The parsed details as a response object. WP_Error if there are errors.
*/ */
public function parse_url_details( $request ) { public function parse_url_details( $request ) {
$url = untrailingslashit( $request['url'] ); $url = untrailingslashit( $request['url'] );
@ -162,10 +177,12 @@ class WP_REST_URL_Details_Controller extends WP_REST_Controller {
/** /**
* Filters the URL data for the response. * Filters the URL data for the response.
* *
* @param WP_REST_Response $response The response object. * @since 5.9.0
* @param string $url The requested URL. *
* @param WP_REST_Request $request Request object. * @param WP_REST_Response $response The response object.
* @param array $remote_url_response HTTP response body from the remote URL. * @param string $url The requested URL.
* @param WP_REST_Request $request Request object.
* @param string $remote_url_response HTTP response body from the remote URL.
*/ */
return apply_filters( 'rest_prepare_url_details', $response, $url, $request, $remote_url_response ); return apply_filters( 'rest_prepare_url_details', $response, $url, $request, $remote_url_response );
} }
@ -175,7 +192,7 @@ class WP_REST_URL_Details_Controller extends WP_REST_Controller {
* *
* @since 5.9.0 * @since 5.9.0
* *
* @return WP_Error|bool True if the request has access, or WP_Error object. * @return WP_Error|bool True if the request has permission, else WP_Error.
*/ */
public function permissions_check() { public function permissions_check() {
if ( current_user_can( 'edit_posts' ) ) { if ( current_user_can( 'edit_posts' ) ) {
@ -200,8 +217,9 @@ class WP_REST_URL_Details_Controller extends WP_REST_Controller {
* *
* @since 5.9.0 * @since 5.9.0
* *
* @param string $url The website url whose HTML we want to access. * @param string $url The website URL whose HTML to access.
* @return string|WP_Error The HTTP response from the remote URL, or an error. * @return string|WP_Error The HTTP response from the remote URL on success.
* WP_Error if no response or no content.
*/ */
private function get_remote_url( $url ) { private function get_remote_url( $url ) {
@ -226,8 +244,10 @@ class WP_REST_URL_Details_Controller extends WP_REST_Controller {
* *
* Can be used to adjust response size limit and other WP_Http::request args. * Can be used to adjust response size limit and other WP_Http::request args.
* *
* @param array $args Arguments used for the HTTP request * @since 5.9.0
* @param string $url The attempted URL. *
* @param array $args Arguments used for the HTTP request.
* @param string $url The attempted URL.
*/ */
$args = apply_filters( 'rest_url_details_http_request_args', $args, $url ); $args = apply_filters( 'rest_url_details_http_request_args', $args, $url );
@ -235,13 +255,21 @@ class WP_REST_URL_Details_Controller extends WP_REST_Controller {
if ( WP_Http::OK !== wp_remote_retrieve_response_code( $response ) ) { if ( WP_Http::OK !== wp_remote_retrieve_response_code( $response ) ) {
// Not saving the error response to cache since the error might be temporary. // Not saving the error response to cache since the error might be temporary.
return new WP_Error( 'no_response', __( 'URL not found. Response returned a non-200 status code for this URL.' ), array( 'status' => WP_Http::NOT_FOUND ) ); return new WP_Error(
'no_response',
__( 'URL not found. Response returned a non-200 status code for this URL.' ),
array( 'status' => WP_Http::NOT_FOUND )
);
} }
$remote_body = wp_remote_retrieve_body( $response ); $remote_body = wp_remote_retrieve_body( $response );
if ( empty( $remote_body ) ) { if ( empty( $remote_body ) ) {
return new WP_Error( 'no_content', __( 'Unable to retrieve body from response at this URL.' ), array( 'status' => WP_Http::NOT_FOUND ) ); return new WP_Error(
'no_content',
__( 'Unable to retrieve body from response at this URL.' ),
array( 'status' => WP_Http::NOT_FOUND )
);
} }
return $remote_body; return $remote_body;
@ -253,18 +281,18 @@ class WP_REST_URL_Details_Controller extends WP_REST_Controller {
* @since 5.9.0 * @since 5.9.0
* *
* @param string $html The HTML from the remote website at URL. * @param string $html The HTML from the remote website at URL.
* @return string The title tag contents on success, or an empty string. * @return string The title tag contents on success. Empty string if not found.
*/ */
private function get_title( $html ) { private function get_title( $html ) {
$pattern = '#<title[^>]*>(.*?)<\s*/\s*title>#is'; $pattern = '#<title[^>]*>(.*?)<\s*/\s*title>#is';
preg_match( $pattern, $html, $match_title ); preg_match( $pattern, $html, $match_title );
$title = ! empty( $match_title[1] ) && is_string( $match_title[1] ) ? trim( $match_title[1] ) : ''; if ( empty( $match_title[1] ) || ! is_string( $match_title[1] ) ) {
if ( empty( $title ) ) {
return ''; return '';
} }
$title = trim( $match_title[1] );
return $this->prepare_metadata_for_output( $title ); return $this->prepare_metadata_for_output( $title );
} }
@ -275,24 +303,24 @@ class WP_REST_URL_Details_Controller extends WP_REST_Controller {
* *
* @param string $html The HTML from the remote website at URL. * @param string $html The HTML from the remote website at URL.
* @param string $url The target website URL. * @param string $url The target website URL.
* @return string The icon URI on success, or an empty string. * @return string The icon URI on success. Empty string if not found.
*/ */
private function get_icon( $html, $url ) { private function get_icon( $html, $url ) {
// Grab the icon's link element. // Grab the icon's link element.
$pattern = '#<link\s[^>]*rel=(?:[\"\']??)\s*(?:icon|shortcut icon|icon shortcut)\s*(?:[\"\']??)[^>]*\/?>#isU'; $pattern = '#<link\s[^>]*rel=(?:[\"\']??)\s*(?:icon|shortcut icon|icon shortcut)\s*(?:[\"\']??)[^>]*\/?>#isU';
preg_match( $pattern, $html, $element ); preg_match( $pattern, $html, $element );
$element = ! empty( $element[0] ) && is_string( $element[0] ) ? trim( $element[0] ) : ''; if ( empty( $element[0] ) || ! is_string( $element[0] ) ) {
if ( empty( $element ) ) {
return ''; return '';
} }
$element = trim( $element[0] );
// Get the icon's href value. // Get the icon's href value.
$pattern = '#href=([\"\']??)([^\" >]*?)\\1[^>]*#isU'; $pattern = '#href=([\"\']??)([^\" >]*?)\\1[^>]*#isU';
preg_match( $pattern, $element, $icon ); preg_match( $pattern, $element, $icon );
$icon = ! empty( $icon[2] ) && is_string( $icon[2] ) ? trim( $icon[2] ) : ''; if ( empty( $icon[2] ) || ! is_string( $icon[2] ) ) {
if ( empty( $icon ) ) {
return ''; return '';
} }
$icon = trim( $icon[2] );
// If the icon is a data URL, return it. // If the icon is a data URL, return it.
$parsed_icon = parse_url( $icon ); $parsed_icon = parse_url( $icon );
@ -319,13 +347,13 @@ class WP_REST_URL_Details_Controller extends WP_REST_Controller {
* @since 5.9.0 * @since 5.9.0
* *
* @param array $meta_elements { * @param array $meta_elements {
* A multi-dimensional indexed array on success, or empty array. * A multi-dimensional indexed array on success, else empty array.
* *
* @type string[] 0 Meta elements with a content attribute. * @type string[] 0 Meta elements with a content attribute.
* @type string[] 1 Content attribute's opening quotation mark. * @type string[] 1 Content attribute's opening quotation mark.
* @type string[] 2 Content attribute's value for each meta element. * @type string[] 2 Content attribute's value for each meta element.
* } * }
* @return string The meta description contents on success, or an empty string. * @return string The meta description contents on success. Empty string if not found.
*/ */
private function get_description( $meta_elements ) { private function get_description( $meta_elements ) {
// Bail out if there are no meta elements. // Bail out if there are no meta elements.
@ -333,7 +361,11 @@ class WP_REST_URL_Details_Controller extends WP_REST_Controller {
return ''; return '';
} }
$description = $this->get_metadata_from_meta_element( $meta_elements, 'name', '(?:description|og:description)' ); $description = $this->get_metadata_from_meta_element(
$meta_elements,
'name',
'(?:description|og:description)'
);
// Bail out if description not found. // Bail out if description not found.
if ( '' === $description ) { if ( '' === $description ) {
@ -344,24 +376,28 @@ class WP_REST_URL_Details_Controller extends WP_REST_Controller {
} }
/** /**
* Parses the Open Graph Image from the provided HTML. * Parses the Open Graph (OG) Image from the provided HTML.
* *
* See: https://ogp.me/. * See: https://ogp.me/.
* *
* @since 5.9.0 * @since 5.9.0
* *
* @param array $meta_elements { * @param array $meta_elements {
* A multi-dimensional indexed array on success, or empty array. * A multi-dimensional indexed array on success, else empty array.
* *
* @type string[] 0 Meta elements with a content attribute. * @type string[] 0 Meta elements with a content attribute.
* @type string[] 1 Content attribute's opening quotation mark. * @type string[] 1 Content attribute's opening quotation mark.
* @type string[] 2 Content attribute's value for each meta element. * @type string[] 2 Content attribute's value for each meta element.
* } * }
* @param string $url The target website URL. * @param string $url The target website URL.
* @return string The OG image on success, or empty string. * @return string The OG image on success. Empty string if not found.
*/ */
private function get_image( $meta_elements, $url ) { private function get_image( $meta_elements, $url ) {
$image = $this->get_metadata_from_meta_element( $meta_elements, 'property', '(?:og:image|og:image:url)' ); $image = $this->get_metadata_from_meta_element(
$meta_elements,
'property',
'(?:og:image|og:image:url)'
);
// Bail out if image not found. // Bail out if image not found.
if ( '' === $image ) { if ( '' === $image ) {
@ -425,7 +461,7 @@ class WP_REST_URL_Details_Controller extends WP_REST_Controller {
* *
* @param string $key The cache key under which to store the value. * @param string $key The cache key under which to store the value.
* @param string $data The data to be stored at the given cache key. * @param string $data The data to be stored at the given cache key.
* @return bool True when transient set. False if fails. * @return bool True when transient set. False if not set.
*/ */
private function set_cache( $key, $data = '' ) { private function set_cache( $key, $data = '' ) {
$ttl = HOUR_IN_SECONDS; $ttl = HOUR_IN_SECONDS;
@ -436,7 +472,9 @@ class WP_REST_URL_Details_Controller extends WP_REST_Controller {
* Can be used to adjust the time until expiration in seconds for the cache * Can be used to adjust the time until expiration in seconds for the cache
* of the data retrieved for the given URL. * of the data retrieved for the given URL.
* *
* @param int $ttl the time until cache expiration in seconds. * @since 5.9.0
*
* @param int $ttl The time until cache expiration in seconds.
*/ */
$cache_expiration = apply_filters( 'rest_url_details_cache_expiration', $ttl ); $cache_expiration = apply_filters( 'rest_url_details_cache_expiration', $ttl );
@ -449,7 +487,7 @@ class WP_REST_URL_Details_Controller extends WP_REST_Controller {
* @since 5.9.0 * @since 5.9.0
* *
* @param string $html The string of HTML to parse. * @param string $html The string of HTML to parse.
* @return string The `<head>..</head>` section on success, or original HTML. * @return string The `<head>..</head>` section on success. Given `$html` if not found.
*/ */
private function get_document_head( $html ) { private function get_document_head( $html ) {
$head_html = $html; $head_html = $html;
@ -487,7 +525,7 @@ class WP_REST_URL_Details_Controller extends WP_REST_Controller {
* *
* @param string $html The string of HTML to be parsed. * @param string $html The string of HTML to be parsed.
* @return array { * @return array {
* A multi-dimensional indexed array on success, or empty array. * A multi-dimensional indexed array on success, else empty array.
* *
* @type string[] 0 Meta elements with a content attribute. * @type string[] 0 Meta elements with a content attribute.
* @type string[] 1 Content attribute's opening quotation mark. * @type string[] 1 Content attribute's opening quotation mark.
@ -567,15 +605,15 @@ class WP_REST_URL_Details_Controller extends WP_REST_Controller {
* @since 5.9.0 * @since 5.9.0
* *
* @param array $meta_elements { * @param array $meta_elements {
* A multi-dimensional indexed array on success, or empty array. * A multi-dimensional indexed array on success, else empty array.
* *
* @type string[] 0 Meta elements with a content attribute. * @type string[] 0 Meta elements with a content attribute.
* @type string[] 1 Content attribute's opening quotation mark. * @type string[] 1 Content attribute's opening quotation mark.
* @type string[] 2 Content attribute's value for each meta element. * @type string[] 2 Content attribute's value for each meta element.
* } * }
* @param string $attr Attribute that identifies the element with the target metadata. * @param string $attr Attribute that identifies the element with the target metadata.
* @param string $attr_value The attribute's value that identifies the element with the target metadata. * @param string $attr_value The attribute's value that identifies the element with the target metadata.
* @return string The metadata on success, or an empty string. * @return string The metadata on success. Empty string if not found.
*/ */
private function get_metadata_from_meta_element( $meta_elements, $attr, $attr_value ) { private function get_metadata_from_meta_element( $meta_elements, $attr, $attr_value ) {
// Bail out if there are no meta elements. // Bail out if there are no meta elements.

View File

@ -16,7 +16,7 @@
* *
* @global string $wp_version * @global string $wp_version
*/ */
$wp_version = '5.9-alpha-52007'; $wp_version = '5.9-alpha-52008';
/** /**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema. * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.