Completed
Push — fix/14475-mapbox-api-private-s... ( a43ec1...9fd069 )
by
unknown
08:10
created

map.php ➔ jetpack_get_mapbox_api_key()   B

Complexity

Conditions 6
Paths 4

Size

Total Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
nc 4
nop 0
dl 0
loc 21
rs 8.9617
c 0
b 0
f 0
1
<?php
2
/**
3
 * Map block.
4
 *
5
 * @since 6.8.0
6
 *
7
 * @package Jetpack
8
 */
9
10
jetpack_register_block(
11
	'jetpack/map',
12
	array(
13
		'render_callback' => 'jetpack_map_block_load_assets',
14
	)
15
);
16
17
/**
18
 * Return the site's own Mapbox API key if set, or the WordPress.com's one otherwise.
19
 *
20
 * @return string
21
 */
22
function jetpack_get_mapbox_api_key() {
23
	$service_api_key = Jetpack_Options::get_option( 'mapbox_api_key' );
24
	if ( $service_api_key ) {
25
		return $service_api_key;
26
	}
27
28
	if ( defined( 'IS_WPCOM' ) && IS_WPCOM && defined( 'WPCOM_MAPBOX_ACCESS_TOKEN' ) ) {
29
		return WPCOM_MAPBOX_ACCESS_TOKEN;
30
	}
31
32
	$endpoint      = rest_url( 'wpcom/v2/service-api-keys/mapbox' );
33
	$response      = wp_remote_get( esc_url_raw( $endpoint ) );
34
	$response_code = wp_remote_retrieve_response_code( $response );
35
36
	if ( 200 === $response_code ) {
37
		$response_body = json_decode( wp_remote_retrieve_body( $response ) );
38
		return $response_body->service_api_key;
39
	}
40
41
	return Jetpack_Options::get_option( 'mapbox_api_key' );
42
}
43
44
/**
45
 * Map block registration/dependency declaration.
46
 *
47
 * @param array  $attr    Array containing the map block attributes.
48
 * @param string $content String containing the map block content.
49
 *
50
 * @return string
51
 */
52
function jetpack_map_block_load_assets( $attr, $content ) {
53
	$api_key = jetpack_get_mapbox_api_key();
54
55
	if ( class_exists( 'Jetpack_AMP_Support' ) && Jetpack_AMP_Support::is_amp_request() ) {
56
		static $map_block_counter = array();
57
58
		$id = get_the_ID();
59
		if ( ! isset( $map_block_counter[ $id ] ) ) {
60
			$map_block_counter[ $id ] = 0;
61
		}
62
		$map_block_counter[ $id ]++;
63
64
		$iframe_url = add_query_arg(
65
			array(
66
				'map-block-counter' => absint( $map_block_counter[ $id ] ),
67
				'map-block-post-id' => $id,
68
			),
69
			get_permalink()
70
		);
71
72
		$placeholder = preg_replace( '/(?<=<div\s)/', 'placeholder ', $content );
73
74
		return sprintf(
75
			'<amp-iframe src="%s" width="%d" height="%d" layout="responsive" allowfullscreen sandbox="allow-scripts">%s</amp-iframe>',
76
			esc_url( $iframe_url ),
77
			4,
78
			3,
79
			$placeholder
80
		);
81
	}
82
83
	Jetpack_Gutenberg::load_assets_as_required( 'map' );
84
85
	return preg_replace( '/<div /', '<div data-api-key="' . esc_attr( $api_key ) . '" ', $content, 1 );
86
}
87
88
/**
89
 * Render a page containing only a single Map block.
90
 */
91
function jetpack_map_block_render_single_block_page() {
92
	// phpcs:ignore WordPress.Security.NonceVerification
93
	$map_block_counter = isset( $_GET, $_GET['map-block-counter'] ) ? absint( $_GET['map-block-counter'] ) : null;
94
	// phpcs:ignore WordPress.Security.NonceVerification
95
	$map_block_post_id = isset( $_GET, $_GET['map-block-post-id'] ) ? absint( $_GET['map-block-post-id'] ) : null;
96
97
	if ( ! $map_block_counter || ! $map_block_post_id ) {
98
		return;
99
	}
100
101
	/* Create an array of all root-level DIVs that are Map Blocks */
102
	$post = get_post( $map_block_post_id );
103
104
	if ( ! class_exists( 'DOMDocument' ) ) {
105
		return;
106
	}
107
108
	$post_html = new DOMDocument();
109
	/** This filter is already documented in core/wp-includes/post-template.php */
110
	$content = apply_filters( 'the_content', $post->post_content );
111
112
	/* Suppress warnings */
113
	libxml_use_internal_errors( true );
114
	@$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...
115
	libxml_use_internal_errors( false );
116
117
	$xpath     = new DOMXPath( $post_html );
118
	$container = $xpath->query( '//div[ contains( @class, "wp-block-jetpack-map" ) ]' )->item( $map_block_counter - 1 );
119
120
	/* Check that we have a block matching the counter position */
121
	if ( ! $container ) {
122
		return;
123
	}
124
125
	/* Compile scripts and styles */
126
	ob_start();
127
128
	add_filter( 'jetpack_is_amp_request', '__return_false' );
129
130
	Jetpack_Gutenberg::load_assets_as_required( 'map' );
131
	wp_scripts()->do_items();
132
	wp_styles()->do_items();
133
134
	add_filter( 'jetpack_is_amp_request', '__return_true' );
135
136
	$head_content = ob_get_clean();
137
138
	/* Put together a new complete document containing only the requested block markup and the scripts/styles needed to render it */
139
	$block_markup = $post_html->saveHTML( $container );
140
	$api_key      = jetpack_get_mapbox_api_key();
141
	$page_html    = sprintf(
142
		'<!DOCTYPE html><head><style>html, body { margin: 0; padding: 0; }</style>%s</head><body>%s</body>',
143
		$head_content,
144
		preg_replace( '/(?<=<div\s)/', 'data-api-key="' . esc_attr( $api_key ) . '" ', $block_markup, 1 )
145
	);
146
	echo $page_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
147
	exit;
148
}
149
150
add_action( 'wp', 'jetpack_map_block_render_single_block_page' );
151