Completed
Push — branch-8.7-built ( 50de0f...7a10d7 )
by Jeremy
32:57 queued 24:29
created

functions.global.php ➔ jetpack_is_mobile()   B

Complexity

Conditions 8
Paths 11

Size

Total Lines 47

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
nc 11
nop 2
dl 0
loc 47
rs 7.9119
c 0
b 0
f 0
1
<?php
2
/**
3
 * This file is meant to be the home for any generic & reusable functions
4
 * that can be accessed anywhere within Jetpack.
5
 *
6
 * This file is loaded whether or not Jetpack is active.
7
 *
8
 * Please namespace with jetpack_
9
 *
10
 * @package Jetpack
11
 */
12
13
use Automattic\Jetpack\Connection\Client;
14
use Automattic\Jetpack\Redirect;
15
use Automattic\Jetpack\Device_Detection;
16
17
/**
18
 * Disable direct access.
19
 */
20
if ( ! defined( 'ABSPATH' ) ) {
21
	exit;
22
}
23
24
/**
25
 * Set the admin language, based on user language.
26
 *
27
 * @since 4.5.0
28
 * @deprecated 6.6.0 Use Core function instead.
29
 *
30
 * @return string
31
 */
32
function jetpack_get_user_locale() {
33
	_deprecated_function( __FUNCTION__, 'jetpack-6.6.0', 'get_user_locale' );
34
	return get_user_locale();
35
}
36
37
/**
38
 * Determine if this site is an Atomic site or not looking first at the 'at_options' option.
39
 * As a fallback, check for presence of wpcomsh plugin to determine if a current site has undergone AT.
40
 *
41
 * @since 4.8.1
42
 *
43
 * @return bool
44
 */
45
function jetpack_is_atomic_site() {
46
	$at_options = get_option( 'at_options', array() );
47
	return ! empty( $at_options ) || defined( 'WPCOMSH__PLUGIN_FILE' );
48
}
49
50
/**
51
 * Register post type for migration.
52
 *
53
 * @since 5.2
54
 */
55
function jetpack_register_migration_post_type() {
56
	register_post_type(
57
		'jetpack_migration',
58
		array(
59
			'supports'     => array(),
60
			'taxonomies'   => array(),
61
			'hierarchical' => false,
62
			'public'       => false,
63
			'has_archive'  => false,
64
			'can_export'   => true,
65
		)
66
	);
67
}
68
69
/**
70
 * Stores migration data in the database.
71
 *
72
 * @since 5.2
73
 *
74
 * @param string $option_name  Option name.
75
 * @param bool   $option_value Option value.
76
 *
77
 * @return int|WP_Error
78
 */
79
function jetpack_store_migration_data( $option_name, $option_value ) {
80
	jetpack_register_migration_post_type();
81
82
	$insert = array(
83
		'post_title'            => $option_name,
84
		'post_content_filtered' => $option_value,
85
		'post_type'             => 'jetpack_migration',
86
		'post_date'             => gmdate( 'Y-m-d H:i:s', time() ),
87
	);
88
89
	$post = get_page_by_title( $option_name, 'OBJECT', 'jetpack_migration' );
90
91
	if ( null !== $post ) {
92
		$insert['ID'] = $post->ID;
93
	}
94
95
	return wp_insert_post( $insert, true );
96
}
97
98
/**
99
 * Retrieves legacy image widget data.
100
 *
101
 * @since 5.2
102
 *
103
 * @param string $option_name Option name.
104
 *
105
 * @return mixed|null
106
 */
107
function jetpack_get_migration_data( $option_name ) {
108
	$post = get_page_by_title( $option_name, 'OBJECT', 'jetpack_migration' );
109
110
	return null !== $post ? maybe_unserialize( $post->post_content_filtered ) : null;
111
}
112
113
/**
114
 * Prints a TOS blurb used throughout the connection prompts.
115
 *
116
 * @since 5.3
117
 *
118
 * @echo string
119
 */
120
function jetpack_render_tos_blurb() {
121
	printf(
122
		wp_kses(
123
			/* Translators: placeholders are links. */
124
			__( 'By clicking the <strong>Set up Jetpack</strong> button, you agree to our <a href="%1$s" target="_blank" rel="noopener noreferrer">Terms of Service</a> and to <a href="%2$s" target="_blank" rel="noopener noreferrer">share details</a> with WordPress.com.', 'jetpack' ),
125
			array(
126
				'a'      => array(
127
					'href'   => array(),
128
					'target' => array(),
129
					'rel'    => array(),
130
				),
131
				'strong' => true,
132
			)
133
		),
134
		esc_url( Redirect::get_url( 'wpcom-tos' ) ),
135
		esc_url( Redirect::get_url( 'jetpack-support-what-data-does-jetpack-sync' ) )
136
	);
137
}
138
139
/**
140
 * Intervene upgrade process so Jetpack themes are downloaded with credentials.
141
 *
142
 * @since 5.3
143
 *
144
 * @param bool   $preempt Whether to preempt an HTTP request's return value. Default false.
145
 * @param array  $r       HTTP request arguments.
146
 * @param string $url     The request URL.
147
 *
148
 * @return array|bool|WP_Error
149
 */
150
function jetpack_theme_update( $preempt, $r, $url ) {
151
	if ( false !== stripos( $url, JETPACK__WPCOM_JSON_API_HOST . '/rest/v1/themes/download' ) ) {
152
		$file = $r['filename'];
153
		if ( ! $file ) {
154
			return new WP_Error( 'problem_creating_theme_file', esc_html__( 'Problem creating file for theme download', 'jetpack' ) );
155
		}
156
		$theme = pathinfo( wp_parse_url( $url, PHP_URL_PATH ), PATHINFO_FILENAME );
157
158
		// Remove filter to avoid endless loop since wpcom_json_api_request_as_blog uses this too.
159
		remove_filter( 'pre_http_request', 'jetpack_theme_update' );
160
		$result = Client::wpcom_json_api_request_as_blog(
161
			"themes/download/$theme.zip",
162
			'1.1',
163
			array(
164
				'stream'   => true,
165
				'filename' => $file,
166
			)
167
		);
168
169
		if ( 200 !== wp_remote_retrieve_response_code( $result ) ) {
170
			return new WP_Error( 'problem_fetching_theme', esc_html__( 'Problem downloading theme', 'jetpack' ) );
171
		}
172
		return $result;
173
	}
174
	return $preempt;
175
}
176
177
/**
178
 * Add the filter when a upgrade is going to be downloaded.
179
 *
180
 * @since 5.3
181
 *
182
 * @param bool $reply Whether to bail without returning the package. Default false.
183
 *
184
 * @return bool
185
 */
186
function jetpack_upgrader_pre_download( $reply ) {
187
	add_filter( 'pre_http_request', 'jetpack_theme_update', 10, 3 );
188
	return $reply;
189
}
190
191
add_filter( 'upgrader_pre_download', 'jetpack_upgrader_pre_download' );
192
193
194
/**
195
 * Wraps data in a way so that we can distinguish between objects and array and also prevent object recursion.
196
 *
197
 * @since 6.1.0
198
 *
199
 * @param array|obj $any        Source data to be cleaned up.
200
 * @param array     $seen_nodes Built array of nodes.
201
 *
202
 * @return array
203
 */
204
function jetpack_json_wrap( &$any, $seen_nodes = array() ) {
205
	if ( is_object( $any ) ) {
206
		$input        = get_object_vars( $any );
207
		$input['__o'] = 1;
208
	} else {
209
		$input = &$any;
210
	}
211
212
	if ( is_array( $input ) ) {
213
		$seen_nodes[] = &$any;
214
215
		$return = array();
216
217
		foreach ( $input as $k => &$v ) {
218
			if ( ( is_array( $v ) || is_object( $v ) ) ) {
219
				if ( in_array( $v, $seen_nodes, true ) ) {
220
					continue;
221
				}
222
				$return[ $k ] = jetpack_json_wrap( $v, $seen_nodes );
0 ignored issues
show
Bug introduced by
It seems like $v can also be of type object; however, jetpack_json_wrap() does only seem to accept array|object<obj>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
223
			} else {
224
				$return[ $k ] = $v;
225
			}
226
		}
227
228
		return $return;
229
	}
230
231
	return $any;
232
}
233
234
/**
235
 * Checks if the mime_content_type function is available and return it if so.
236
 *
237
 * The function mime_content_type is enabled by default in PHP, but can be disabled. We attempt to
238
 * enforce this via composer.json, but that won't be checked in majority of cases where
239
 * this would be happening.
240
 *
241
 * @since 7.8.0
242
 *
243
 * @param string $file File location.
244
 *
245
 * @return string|false MIME type or false if functionality is not available.
246
 */
247
function jetpack_mime_content_type( $file ) {
248
	if ( function_exists( 'mime_content_type' ) ) {
249
		return mime_content_type( $file );
250
	}
251
252
	return false;
253
}
254
255
/**
256
 * Checks that the mime type of the specified file is among those in a filterable list of mime types.
257
 *
258
 * @since 7.8.0
259
 *
260
 * @param string $file Path to file to get its mime type.
261
 *
262
 * @return bool
263
 */
264
function jetpack_is_file_supported_for_sideloading( $file ) {
265
	$type = jetpack_mime_content_type( $file );
266
267
	if ( ! $type ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $type of type string|false is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
268
		return false;
269
	}
270
271
	/**
272
	 * Filter the list of supported mime types for media sideloading.
273
	 *
274
	 * @since 4.0.0
275
	 *
276
	 * @module json-api
277
	 *
278
	 * @param array $supported_mime_types Array of the supported mime types for media sideloading.
279
	 */
280
	$supported_mime_types = apply_filters(
281
		'jetpack_supported_media_sideload_types',
282
		array(
283
			'image/png',
284
			'image/jpeg',
285
			'image/gif',
286
			'image/bmp',
287
			'video/quicktime',
288
			'video/mp4',
289
			'video/mpeg',
290
			'video/ogg',
291
			'video/3gpp',
292
			'video/3gpp2',
293
			'video/h261',
294
			'video/h262',
295
			'video/h264',
296
			'video/x-msvideo',
297
			'video/x-ms-wmv',
298
			'video/x-ms-asf',
299
		)
300
	);
301
302
	// If the type returned was not an array as expected, then we know we don't have a match.
303
	if ( ! is_array( $supported_mime_types ) ) {
304
		return false;
305
	}
306
307
	return in_array( $type, $supported_mime_types, true );
308
}
309
310
/**
311
 * Determine if the current User Agent matches the passed $kind
312
 *
313
 * @param string $kind Category of mobile device to check for.
314
 *                         Either: any, dumb, smart.
315
 * @param bool   $return_matched_agent Boolean indicating if the UA should be returned.
316
 *
317
 * @return bool|string Boolean indicating if current UA matches $kind. If
318
 *                              $return_matched_agent is true, returns the UA string
319
 */
320
function jetpack_is_mobile( $kind = 'any', $return_matched_agent = false ) {
321
322
	/**
323
	 * Filter the value of jetpack_is_mobile before it is calculated.
324
	 *
325
	 * Passing a truthy value to the filter will short-circuit determining the
326
	 * mobile type, returning the passed value instead.
327
	 *
328
	 * @since  4.2.0
329
	 *
330
	 * @param bool|string $matches Boolean if current UA matches $kind or not. If
331
	 *                             $return_matched_agent is true, should return the UA string
332
	 * @param string      $kind Category of mobile device being checked
333
	 * @param bool        $return_matched_agent Boolean indicating if the UA should be returned
334
	 */
335
	$pre = apply_filters( 'pre_jetpack_is_mobile', null, $kind, $return_matched_agent );
336
	if ( $pre ) {
337
		return $pre;
338
	}
339
340
	$return      = false;
341
	$device_info = Device_Detection::get_info();
342
343
	if ( 'any' === $kind ) {
344
		$return = $device_info['is_phone'];
345
	} elseif ( 'smart' === $kind ) {
346
		$return = $device_info['is_smartphone'];
347
	} elseif ( 'dumb' === $kind ) {
348
		$return = $device_info['is_phone'] && ! $device_info['is_smartphone'];
349
	}
350
351
	if ( $return_matched_agent && true === $return ) {
352
		$return = $device_info['is_phone_matched_ua'];
353
	}
354
355
	/**
356
	 * Filter the value of jetpack_is_mobile
357
	 *
358
	 * @since  4.2.0
359
	 *
360
	 * @param bool|string $matches Boolean if current UA matches $kind or not. If
361
	 *                             $return_matched_agent is true, should return the UA string
362
	 * @param string      $kind Category of mobile device being checked
363
	 * @param bool        $return_matched_agent Boolean indicating if the UA should be returned
364
	 */
365
	return apply_filters( 'jetpack_is_mobile', $return, $kind, $return_matched_agent );
366
}
367