Completed
Push — try/map-block-add-static-image... ( 0764ee...420bf0 )
by
unknown
364:48 queued 354:24
created

map.php ➔ render_static_map_image_block()   F

Complexity

Conditions 22
Paths > 20000

Size

Total Lines 78

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 22
nc 39936
nop 3
dl 0
loc 78
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

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
 * Map block.
4
 *
5
 * @since 6.8.0
6
 *
7
 * @package automattic/jetpack
8
 */
9
10
namespace Automattic\Jetpack\Extensions\Map;
11
12
use Automattic\Jetpack\Blocks;
13
use Automattic\Jetpack\Tracking;
14
use Jetpack;
15
use Jetpack_Gutenberg;
16
use Jetpack_Mapbox_Helper;
17
18
const FEATURE_NAME = 'map';
19
const BLOCK_NAME   = 'jetpack/' . FEATURE_NAME;
20
21
if ( ! class_exists( 'Jetpack_Mapbox_Helper' ) ) {
22
	\jetpack_require_lib( 'class-jetpack-mapbox-helper' );
23
}
24
25
/**
26
 * Registers the block for use in Gutenberg
27
 * This is done via an action so that we can disable
28
 * registration if we need to.
29
 */
30
function register_block() {
31
	Blocks::jetpack_register_block(
32
		BLOCK_NAME,
33
		array(
34
			'render_callback' => __NAMESPACE__ . '\load_assets',
35
		)
36
	);
37
}
38
add_action( 'init', __NAMESPACE__ . '\register_block' );
39
40
/**
41
 * Record a Tracks event every time the Map block is loaded on WordPress.com and Atomic.
42
 *
43
 * @param string $access_token_source The Mapbox API access token source.
44
 */
45
function wpcom_load_event( $access_token_source ) {
46
	if ( 'wpcom' !== $access_token_source ) {
47
		return;
48
	}
49
50
	$event_name = 'map_block_mapbox_wpcom_key_load';
51
	if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
52
		jetpack_require_lib( 'tracks/client' );
53
		tracks_record_event( wp_get_current_user(), $event_name );
54
	} elseif ( jetpack_is_atomic_site() && Jetpack::is_active() ) {
55
		$tracking = new Tracking();
56
		$tracking->record_user_event( $event_name );
57
	}
58
}
59
60
/**
61
 * Map block registration/dependency declaration.
62
 *
63
 * @param array  $attr    Array containing the map block attributes.
64
 * @param string $content String containing the map block content.
65
 *
66
 * @return string
67
 */
68
function load_assets( $attr, $content ) {
69
	$access_token = Jetpack_Mapbox_Helper::get_access_token();
70
71
	wpcom_load_event( $access_token['source'] );
72
73
	if ( Blocks::is_amp_request() ) {
74
		static $map_block_counter = array();
75
76
		$id = get_the_ID();
77
		if ( ! isset( $map_block_counter[ $id ] ) ) {
78
			$map_block_counter[ $id ] = 0;
79
		}
80
		$map_block_counter[ $id ]++;
81
82
		$iframe_url = add_query_arg(
83
			array(
84
				'map-block-counter' => absint( $map_block_counter[ $id ] ),
85
				'map-block-post-id' => $id,
86
			),
87
			get_permalink()
88
		);
89
90
		$placeholder = preg_replace( '/(?<=<div\s)/', 'placeholder ', $content );
91
92
		return sprintf(
93
			'<amp-iframe src="%s" width="%d" height="%d" layout="responsive" allowfullscreen sandbox="allow-scripts">%s</amp-iframe>',
94
			esc_url( $iframe_url ),
95
			4,
96
			3,
97
			$placeholder
98
		);
99
	}
100
101
	// TODO: See if we can skip loading JS if the $attr['isStaticMap'] attribute is set.
102
	Jetpack_Gutenberg::load_assets_as_required( FEATURE_NAME );
103
104
	if ( ! empty( $attr['isStaticMap'] ) && true === boolval( $attr['isStaticMap'] ) ) {
105
		return render_static_map_image_block( $attr, $content, $access_token['key'] );
106
	}
107
108
	return preg_replace( '/<div /', '<div data-api-key="' . esc_attr( $access_token['key'] ) . '" ', $content, 1 );
109
}
110
111
/**
112
 * Render a map image using the Mapbox Static Images API
113
 *
114
 * @param array  $attr             Array containing the map block attributes.
115
 * @param string $content          String containing the map block content.
116
 * @param string $access_token_key Mapbox access token key to be used for the static image API request.
117
 *
118
 * @return string Block content markup containing a static image URL.
119
 */
120
function render_static_map_image_block( $attr, $content, $access_token_key ) {
121
	// Set default and passed in values to be used in generating the image url.
122
	$width        = 1000;
123
	$height       = isset( $attr['mapHeight'] ) && is_numeric( $attr['mapHeight'] ) ? $attr['mapHeight'] : 400;
124
	$zoom         = isset( $attr['zoom'] ) && is_numeric( $attr['zoom'] ) ? $attr['zoom'] : 13;
125
	$bearing      = 0;
126
	$longitude    = is_numeric( $attr['mapCenter']['lng'] ) ? $attr['mapCenter']['lng'] : -122.41941550000001;
127
	$latitude     = is_numeric( $attr['mapCenter']['lat'] ) ? $attr['mapCenter']['lat'] : 37.7749295;
128
	$show_streets = isset( $attr['mapDetails'] ) && false === $attr['mapDetails'] ? false : true;
129
	$marker_color = 'ff0000'; // Default to bright red.
130
131
	// Use custom marker color if provided colour is a valid hex code.
132
	if ( isset( $attr['markerColor'] ) ) {
133
		$stripped_color = str_replace( '#', '', $attr['markerColor'] );
134
		if ( \ctype_xdigit( $stripped_color ) ) {
135
			$marker_color = $stripped_color;
136
		}
137
	}
138
139
	// Generate slug for all markers on the map.
140
	$markers_slug = '';
141
	if ( ! empty( $attr['points'] ) ) {
142
		foreach ( $attr['points'] as $point ) {
143
			$marker  = empty( $markers_slug ) ? '' : ',';
144
			$marker .= 'pin-s+' . $marker_color;
145
			if (
146
				is_numeric( $point['coordinates']['longitude'] ) &&
147
				is_numeric( $point['coordinates']['latitude'] )
148
			) {
149
				$marker       .= sprintf(
150
					'(%s,%s)',
151
					$point['coordinates']['longitude'],
152
					$point['coordinates']['latitude']
153
				);
154
				$markers_slug .= $marker;
155
			}
156
		}
157
	}
158
	if ( ! empty( $markers_slug ) ) {
159
		$markers_slug .= '/';
160
	}
161
162
	// Set the type of map or map style, known in the Static Image API as an overlay.
163
	// Default to basic / street overlay.
164
	$overlay = 'streets-v11';
165
	if ( isset( $attr['className'] ) ) {
166
		if ( 'is-style-satellite' === $attr['className'] ) {
167
			if ( $show_streets ) {
168
				$overlay = 'satellite-streets-v11';
169
			} else {
170
				$overlay = 'satellite-v9';
171
			}
172
		}
173
174
		if ( 'is-style-black_and_white' === $attr['className'] ) {
175
			$overlay = 'light-v10';
176
		}
177
178
		if ( 'is-style-terrain' === $attr['className'] ) {
179
			$overlay = 'outdoors-v11';
180
		}
181
	}
182
183
	// Generate a Mapbox Image API URL in the appropriate format:
184
	// https://api.mapbox.com/styles/v1/mapbox/streets-v11/static/pin-s+555555(-77,52),pin-s+555555(-77.5,54)/-77.25,53.0116,6,0/1000x4002x?access_token=YOUR_MAPBOX_ACCESS_TOKEN.
185
186
	$url_base       = 'https://api.mapbox.com/styles/v1/mapbox';
187
	$url_with_paths = "{$url_base}/{$overlay}/static/{$markers_slug}{$longitude},{$latitude},{$zoom},{$bearing}/{$width}x{$height}@2x";
188
189
	$url = add_query_arg(
190
		array(
191
			'access_token' => $access_token_key,
192
		),
193
		$url_with_paths
194
	);
195
196
	return '<div class="wp-block-jetpack-map--static_image"><img src="' . $url . '" /></div>';
197
}
198
199
/**
200
 * Render a page containing only a single Map block.
201
 */
202
function render_single_block_page() {
203
	// phpcs:ignore WordPress.Security.NonceVerification
204
	$map_block_counter = isset( $_GET, $_GET['map-block-counter'] ) ? absint( $_GET['map-block-counter'] ) : null;
205
	// phpcs:ignore WordPress.Security.NonceVerification
206
	$map_block_post_id = isset( $_GET, $_GET['map-block-post-id'] ) ? absint( $_GET['map-block-post-id'] ) : null;
207
208
	if ( ! $map_block_counter || ! $map_block_post_id ) {
209
		return;
210
	}
211
212
	/* Create an array of all root-level DIVs that are Map Blocks */
213
	$post = get_post( $map_block_post_id );
214
215
	if ( ! class_exists( 'DOMDocument' ) ) {
216
		return;
217
	}
218
219
	$post_html = new \DOMDocument();
220
	/** This filter is already documented in core/wp-includes/post-template.php */
221
	$content = apply_filters( 'the_content', $post->post_content );
222
223
	/* Suppress warnings */
224
	libxml_use_internal_errors( true );
225
	@$post_html->loadHTML( $content ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
226
	libxml_use_internal_errors( false );
227
228
	$xpath     = new \DOMXPath( $post_html );
229
	$container = $xpath->query( '//div[ contains( @class, "wp-block-jetpack-map" ) ]' )->item( $map_block_counter - 1 );
230
231
	/* Check that we have a block matching the counter position */
232
	if ( ! $container ) {
233
		return;
234
	}
235
236
	/* Compile scripts and styles */
237
	ob_start();
238
239
	add_filter( 'jetpack_is_amp_request', '__return_false' );
240
241
	Jetpack_Gutenberg::load_assets_as_required( FEATURE_NAME );
242
	wp_scripts()->do_items();
243
	wp_styles()->do_items();
244
245
	add_filter( 'jetpack_is_amp_request', '__return_true' );
246
247
	$head_content = ob_get_clean();
248
249
	/* Put together a new complete document containing only the requested block markup and the scripts/styles needed to render it */
250
	$block_markup = $post_html->saveHTML( $container );
251
	$access_token = Jetpack_Mapbox_Helper::get_access_token();
252
	$page_html    = sprintf(
253
		'<!DOCTYPE html><head><style>html, body { margin: 0; padding: 0; }</style>%s</head><body>%s</body>',
254
		$head_content,
255
		preg_replace( '/(?<=<div\s)/', 'data-api-key="' . esc_attr( $access_token['key'] ) . '" ', $block_markup, 1 )
256
	);
257
	echo $page_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
258
	exit;
259
}
260
add_action( 'wp', __NAMESPACE__ . '\render_single_block_page' );
261