Completed
Push — fusion-sync/yoavf/D58903-code-... ( 503586 )
by
unknown
10:29
created

map.php ➔ map_block_from_geo_points()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 20
rs 9.6
c 0
b 0
f 0
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
	Jetpack_Gutenberg::load_assets_as_required( FEATURE_NAME );
102
103
	return preg_replace( '/<div /', '<div data-api-key="' . esc_attr( $access_token['key'] ) . '" ', $content, 1 );
104
}
105
106
/**
107
 * Render a page containing only a single Map block.
108
 */
109
function render_single_block_page() {
110
	// phpcs:ignore WordPress.Security.NonceVerification
111
	$map_block_counter = isset( $_GET, $_GET['map-block-counter'] ) ? absint( $_GET['map-block-counter'] ) : null;
112
	// phpcs:ignore WordPress.Security.NonceVerification
113
	$map_block_post_id = isset( $_GET, $_GET['map-block-post-id'] ) ? absint( $_GET['map-block-post-id'] ) : null;
114
115
	if ( ! $map_block_counter || ! $map_block_post_id ) {
116
		return;
117
	}
118
119
	/* Create an array of all root-level DIVs that are Map Blocks */
120
	$post = get_post( $map_block_post_id );
121
122
	if ( ! class_exists( 'DOMDocument' ) ) {
123
		return;
124
	}
125
126
	$post_html = new \DOMDocument();
127
	/** This filter is already documented in core/wp-includes/post-template.php */
128
	$content = apply_filters( 'the_content', $post->post_content );
129
130
	/* Suppress warnings */
131
	libxml_use_internal_errors( true );
132
	@$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...
133
	libxml_use_internal_errors( false );
134
135
	$xpath     = new \DOMXPath( $post_html );
136
	$container = $xpath->query( '//div[ contains( @class, "wp-block-jetpack-map" ) ]' )->item( $map_block_counter - 1 );
137
138
	/* Check that we have a block matching the counter position */
139
	if ( ! $container ) {
140
		return;
141
	}
142
143
	/* Compile scripts and styles */
144
	ob_start();
145
146
	add_filter( 'jetpack_is_amp_request', '__return_false' );
147
148
	Jetpack_Gutenberg::load_assets_as_required( FEATURE_NAME );
149
	wp_scripts()->do_items();
150
	wp_styles()->do_items();
151
152
	add_filter( 'jetpack_is_amp_request', '__return_true' );
153
154
	$head_content = ob_get_clean();
155
156
	/* Put together a new complete document containing only the requested block markup and the scripts/styles needed to render it */
157
	$block_markup = $post_html->saveHTML( $container );
158
	$access_token = Jetpack_Mapbox_Helper::get_access_token();
159
	$page_html    = sprintf(
160
		'<!DOCTYPE html><head><style>html, body { margin: 0; padding: 0; }</style>%s</head><body>%s</body>',
161
		$head_content,
162
		preg_replace( '/(?<=<div\s)/', 'data-api-key="' . esc_attr( $access_token['key'] ) . '" ', $block_markup, 1 )
163
	);
164
	echo $page_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
165
	exit;
166
}
167
add_action( 'wp', __NAMESPACE__ . '\render_single_block_page' );
168
169
/**
170
 * Helper function to generate the markup of the block in PHP.
171
 *
172
 * @param Array $points - Array containing geo location points.
173
 *
174
 * @return string Markup for the jetpack/map block.
175
 */
176
function map_block_from_geo_points( $points ) {
177
	$map_block_data = [
178
		'points' => $points,
179
		'zoom' => 1,
180
		'mapCenter' => [
181
			'lng' => $points[0]['coordinates']['longitude'],
182
			'lat' => $points[0]['coordinates']['latitude'],
183
		],
184
	];
185
186
	$map_block = '<!-- wp:jetpack/map ' . json_encode( $map_block_data ) . ' -->' . PHP_EOL;
187
	$map_block .= sprintf(
188
		'<div class="wp-block-jetpack-map" data-map-style="default" data-map-details="true" data-points="%1$s" data-zoom="1" data-map-center="%2$s" data-marker-color="red"></div>',
189
		esc_html( json_encode( $map_block_data['points'] ) ),
190
		esc_html( json_encode( $map_block_data['mapCenter'] ) )
191
	) . PHP_EOL;
192
	$map_block .= '<!-- /wp:jetpack/map -->';
193
194
	return $map_block;
195
}
196