Completed
Push — renovate/mocha-8.x ( 07030e...e8e64c )
by
unknown
28:17 queued 19:09
created

pinterest.php ➔ render_amp_pin()   C

Complexity

Conditions 9
Paths 98

Size

Total Lines 76

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
nc 98
nop 1
dl 0
loc 76
rs 6.968
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Pinterest Block.
4
 *
5
 * @since 8.0.0
6
 *
7
 * @package Jetpack
8
 */
9
10
namespace Automattic\Jetpack\Extensions\Pinterest;
11
12
use Jetpack_AMP_Support;
13
use WP_Error;
14
15
const FEATURE_NAME = 'pinterest';
16
const BLOCK_NAME   = 'jetpack/' . FEATURE_NAME;
17
const URL_PATTERN  = '#^https?://(?:www\.)?(?:[a-z]{2}\.)?pinterest\.[a-z.]+/pin/(?P<pin_id>[^/]+)/?#i'; // Taken from AMP plugin, originally from Jetpack.
18
19
/**
20
 * Registers the block for use in Gutenberg
21
 * This is done via an action so that we can disable
22
 * registration if we need to.
23
 */
24
function register_block() {
25
	jetpack_register_block(
26
		BLOCK_NAME,
27
		array( 'render_callback' => __NAMESPACE__ . '\load_assets' )
28
	);
29
}
30
add_action( 'init', __NAMESPACE__ . '\register_block' );
31
32
/**
33
 * Fetch info for a Pin.
34
 *
35
 * This is using the same pin info API as AMP is using client-side in the amp-pinterest component.
36
 * Successful API responses are cached in a transient for 1 month. Unsuccessful responses are cached for 1 hour.
37
 *
38
 * @link https://github.com/ampproject/amphtml/blob/b5dea36e0b8bd012585d50839766a084f99a3685/extensions/amp-pinterest/0.1/pin-widget.js#L83-L97
39
 * @param string $pin_id Pin ID.
40
 * @return array|WP_Error Pin info or error on failure.
41
 */
42
function fetch_pin_info( $pin_id ) {
43
	$transient_id = substr( "jetpack_pin_info_{$pin_id}", 0, 172 );
44
45
	$info = get_transient( $transient_id );
46
	if ( is_array( $info ) || is_wp_error( $info ) ) {
47
		return $info;
48
	}
49
50
	$pin_info_api_url = add_query_arg(
51
		array(
52
			'pin_ids'     => rawurlencode( $pin_id ),
53
			'sub'         => 'wwww',
54
			'base_scheme' => 'https',
55
		),
56
		'https://widgets.pinterest.com/v3/pidgets/pins/info/'
57
	);
58
59
	$response = wp_remote_get( esc_url_raw( $pin_info_api_url ) );
60
	if ( is_wp_error( $response ) ) {
61
		set_transient( $transient_id, $response, HOUR_IN_SECONDS );
62
		return $response;
63
	}
64
65
	$error = null;
66
	$body  = json_decode( wp_remote_retrieve_body( $response ), true );
67
	if ( ! is_array( $body ) || ! isset( $body['status'] ) ) {
68
		$error = new WP_Error( 'bad_json_response', '', compact( 'pin_id' ) );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'bad_json_response'.

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 @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
69
	} elseif ( 'success' !== $body['status'] || ! isset( $body['data'][0] ) ) {
70
		$error = new WP_Error( 'unsuccessful_request', '', compact( 'pin_id' ) );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'unsuccessful_request'.

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 @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
71
	} elseif ( ! isset( $body['data'][0]['images']['237x'] ) ) {
72
		// See <https://github.com/ampproject/amphtml/blob/b5dea36e0b8bd012585d50839766a084f99a3685/extensions/amp-pinterest/0.1/pin-widget.js#L106>.
73
		$error = new WP_Error( 'missing_required_image', '', compact( 'pin_id' ) );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'missing_required_image'.

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 @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
74
	}
75
76
	if ( $error ) {
77
		set_transient( $transient_id, $error, HOUR_IN_SECONDS );
78
		return $error;
79
	} else {
80
		$data = $body['data'][0];
81
		set_transient( $transient_id, $data, MONTH_IN_SECONDS );
82
		return $data;
83
	}
84
}
85
86
/**
87
 * Render a Pin using the amp-pinterest component.
88
 *
89
 * This does not render boards or user profiles.
90
 *
91
 * Since AMP components need to be statically sized to be valid (so as to avoid layout shifting), there are quite a few
92
 * hard-coded numbers as taken from the CSS for the AMP component.
93
 *
94
 * @param array $attr Block attributes.
95
 * @return string Markup for <amp-pinterest>.
96
 */
97
function render_amp_pin( $attr ) {
98
	$info = null;
99
	if ( preg_match( URL_PATTERN, $attr['url'], $matches ) ) {
100
		$info = fetch_pin_info( $matches['pin_id'] );
101
	}
102
103
	if ( is_array( $info ) ) {
104
		$image       = $info['images']['237x'];
105
		$title       = isset( $info['rich_metadata']['title'] ) ? $info['rich_metadata']['title'] : null;
106
		$description = isset( $info['rich_metadata']['description'] ) ? $info['rich_metadata']['description'] : null;
107
108
		// This placeholder will appear while waiting for the amp-pinterest component to initialize (or if it fails to initialize due to JS being disabled).
109
		$placeholder = sprintf(
110
			// The AMP_Img_Sanitizer will convert his to <amp-img> while also supplying `noscript > img` as fallback when JS is disabled.
111
			'<a href="%s" placeholder><img src="%s" alt="%s" layout="fill" object-fit="contain" object-position="top left"></a>',
112
			esc_url( $attr['url'] ),
113
			esc_url( $image['url'] ),
114
			esc_attr( $title )
115
		);
116
117
		$amp_padding     = 5;   // See <https://github.com/ampproject/amphtml/blob/b5dea36e0b8bd012585d50839766a084f99a3685/extensions/amp-pinterest/0.1/amp-pinterest.css#L269>.
118
		$amp_fixed_width = 237; // See <https://github.com/ampproject/amphtml/blob/b5dea36e0b8bd012585d50839766a084f99a3685/extensions/amp-pinterest/0.1/amp-pinterest.css#L270>.
119
		$pin_info_height = 60;  // Minimum Obtained by measuring the height of the .-amp-pinterest-embed-pin-text element.
120
121
		// Add height based on how much description there is. There are roughly 30 characters on a line of description text.
122
		$has_description = false;
123
		if ( ! empty( $info['description'] ) ) {
124
			$desc_padding_top = 5;  // See <https://github.com/ampproject/amphtml/blob/b5dea36e0b8bd012585d50839766a084f99a3685/extensions/amp-pinterest/0.1/amp-pinterest.css#L342>.
125
			$pin_info_height += $desc_padding_top;
126
127
			// Trim whitespace on description if there is any left, use to calculate the likely rows of text.
128
			$description = trim( $info['description'] );
129
			if ( strlen( $description ) > 0 ) {
130
				$has_description  = true;
131
				$desc_line_height = 17; // See <https://github.com/ampproject/amphtml/blob/b5dea36e0b8bd012585d50839766a084f99a3685/extensions/amp-pinterest/0.1/amp-pinterest.css#L341>.
132
				$pin_info_height += ceil( strlen( $description ) / 30 ) * $desc_line_height;
133
			}
134
		}
135
136
		if ( ! empty( $info['repin_count'] ) ) {
137
			$pin_stats_height = 16;  // See <https://github.com/ampproject/amphtml/blob/b5dea36e0b8bd012585d50839766a084f99a3685/extensions/amp-pinterest/0.1/amp-pinterest.css#L322>.
138
			$pin_info_height += $pin_stats_height;
139
		}
140
141
		// When Pin description is empty, make sure title and description from rich metadata are supplied for accessibility and discoverability.
142
		$title = $has_description ? '' : implode( "\n", array_filter( array( $title, $description ) ) );
143
144
		$amp_pinterest = sprintf(
145
			'<amp-pinterest style="%1$s" data-do="embedPin" data-url="%2$s" width="%3$d" height="%4$d" title="%5$s">%6$s</amp-pinterest>',
146
			esc_attr( 'line-height:1.5; font-size:21px' ), // Override styles from theme due to precise height calculations above.
147
			esc_url( $attr['url'] ),
148
			$amp_fixed_width + ( $amp_padding * 2 ),
149
			$image['height'] + $pin_info_height + ( $amp_padding * 2 ),
150
			esc_attr( $title ),
151
			$placeholder
152
		);
153
	} else {
154
		// Fallback embed when info is not available.
155
		$amp_pinterest = sprintf(
156
			'<amp-pinterest data-do="embedPin" data-url="%1$s" width="%2$d" height="%3$d">%4$s</amp-pinterest>',
157
			esc_url( $attr['url'] ),
158
			450, // Fallback width.
159
			750, // Fallback height.
160
			sprintf(
161
				'<a placeholder href="%s">%s</a>',
162
				esc_url( $attr['url'] ),
163
				esc_html( $attr['url'] )
164
			)
165
		);
166
	}
167
168
	return sprintf(
169
		'<div class="wp-block-jetpack-pinterest">%s</div>',
170
		$amp_pinterest
171
	);
172
}
173
174
/**
175
 * Pinterest block registration/dependency declaration.
176
 *
177
 * @param array  $attr    Array containing the Pinterest block attributes.
178
 * @param string $content String containing the Pinterest block content.
179
 *
180
 * @return string
181
 */
182
function load_assets( $attr, $content ) {
183
	if ( class_exists( 'Jetpack_AMP_Support' ) && Jetpack_AMP_Support::is_amp_request() ) {
184
		return render_amp_pin( $attr );
185
	} else {
186
		wp_enqueue_script( 'pinterest-pinit', 'https://assets.pinterest.com/js/pinit.js', array(), JETPACK__VERSION, true );
187
		return $content;
188
	}
189
}
190