Completed
Push — add/is-active-to-connection-pa... ( 30e22c )
by
unknown
18:06 queued 10:36
created

class.jetpack-jitm.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/**
4
 * Jetpack just in time messaging through out the admin
5
 *
6
 * @since 3.7.0
7
 */
8
class Jetpack_JITM {
9
10
	/**
11
	 * @var Jetpack_JITM
12
	 **/
13
	private static $instance = null;
14
15
	/**
16
	 * Initializes the class, or returns the singleton
17
	 *
18
	 * @return Jetpack_JITM | false
19
	 */
20
	static function init() {
21
		/**
22
		 * Filter to turn off all just in time messages
23
		 *
24
		 * @since 3.7.0
25
		 * @since 5.4.0 Correct docblock to reflect default arg value
26
		 *
27
		 * @param bool false Whether to show just in time messages.
28
		 */
29
		if ( ! apply_filters( 'jetpack_just_in_time_msgs', false ) ) {
30
			return false;
31
		}
32
33
		if ( is_null( self::$instance ) ) {
34
			self::$instance = new Jetpack_JITM;
35
		}
36
37
		return self::$instance;
38
	}
39
40
	/**
41
	 * Jetpack_JITM constructor.
42
	 */
43
	private function __construct() {
44
		if ( ! Jetpack::is_active() || Jetpack::is_development_mode() ) {
0 ignored issues
show
Deprecated Code introduced by
The method Jetpack::is_active() has been deprecated with message: 7.5 Use Connection_Manager instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
45
			return;
46
		}
47
		add_action( 'current_screen', array( $this, 'prepare_jitms' ) );
48
	}
49
50
	/**
51
	 * Get's the Jetpack emblem
52
	 *
53
	 * @return string The Jetpack emblem
54
	 */
55
	function get_emblem() {
56
		return '<div class="jp-emblem">' . Jetpack::get_jp_emblem() . '</div>';
57
	}
58
59
	/**
60
	 * Prepare actions according to screen and post type.
61
	 *
62
	 * @since 3.8.2
63
	 *
64
	 * @uses Jetpack_Autoupdate::get_possible_failures()
65
	 *
66
	 * @param object $screen
67
	 */
68
	function prepare_jitms( $screen ) {
69
		if ( ! in_array( $screen->id, array(
70
			'jetpack_page_stats',
71
			'jetpack_page_akismet-key-config',
72
			'admin_page_jetpack_modules'
73
		) ) ) {
74
			add_action( 'admin_enqueue_scripts', array( $this, 'jitm_enqueue_files' ) );
75
			add_action( 'admin_notices', array( $this, 'ajax_message' ) );
76
			add_action( 'edit_form_top', array( $this, 'ajax_message' ) );
77
		}
78
	}
79
80
	/**
81
	 * A special filter for WooCommerce, to set a message based on local state.
82
	 *
83
	 * @param $message string The current message
84
	 *
85
	 * @return array The new message
86
	 */
87
	static function jitm_woocommerce_services_msg( $content ) {
88
		if ( ! function_exists( 'wc_get_base_location' ) ) {
89
			return $content;
90
		}
91
92
		$base_location = wc_get_base_location();
93
94
		switch ( $base_location['country'] ) {
95
			case 'US':
96
				$content->message = esc_html__( 'New free service: Show USPS shipping rates on your store! Added bonus: print shipping labels without leaving WooCommerce.', 'jetpack' );
97
				break;
98
			case 'CA':
99
				$content->message = esc_html__( 'New free service: Show Canada Post shipping rates on your store!', 'jetpack' );
100
				break;
101
			default:
102
				$content->message = '';
103
		}
104
105
		return $content;
106
	}
107
108
	/**
109
	 * A special filter for WooCommerce Call To Action button
110
	 *
111
	 * @param $CTA string The existing CTA
112
	 *
113
	 * @return string The new CTA
114
	 */
115
	static function jitm_jetpack_woo_services_install( $CTA ) {
116
		return wp_nonce_url( add_query_arg( array(
117
			'wc-services-action' => 'install'
118
		), admin_url( 'admin.php?page=wc-settings' ) ), 'wc-services-install' );
119
	}
120
121
	/**
122
	 * A special filter for WooCommerce Call To Action button
123
	 *
124
	 * @param $CTA string The existing CTA
125
	 *
126
	 * @return string The new CTA
127
	 */
128
	static function jitm_jetpack_woo_services_activate( $CTA ) {
129
		return wp_nonce_url( add_query_arg( array(
130
			'wc-services-action' => 'activate'
131
		), admin_url( 'admin.php?page=wc-settings' ) ), 'wc-services-install' );
132
	}
133
134
	/**
135
	 * Injects the dom to show a JITM inside of
136
	 */
137
	function ajax_message() {
138
		$message_path = $this->get_message_path();
139
		$query_string = _http_build_query( $_GET, '', ',' );
140
		$current_screen = wp_unslash( $_SERVER['REQUEST_URI'] );
141
		?>
142
		<div class="jetpack-jitm-message"
143
		     data-nonce="<?php echo wp_create_nonce( 'wp_rest' ) ?>"
144
		     data-message-path="<?php echo esc_attr( $message_path ) ?>"
145
		     data-query="<?php echo urlencode_deep( $query_string ) ?>"
146
		     data-redirect="<?php echo urlencode_deep( $current_screen ) ?>"
147
		></div>
148
		<?php
149
	}
150
151
	/**
152
	 * Get's the current message path for display of a JITM
153
	 *
154
	 * @return string The message path
155
	 */
156
	function get_message_path() {
157
		$screen = get_current_screen();
158
159
		return 'wp:' . $screen->id . ':' . current_filter();
160
	}
161
162
	/**
163
	 * Function to enqueue jitm css and js
164
	 */
165
	function jitm_enqueue_files() {
166
		$min = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '' : '.min';
167
		wp_register_style(
168
			'jetpack-jitm-css',
169
			plugins_url( "css/jetpack-admin-jitm{$min}.css", JETPACK__PLUGIN_FILE ),
170
			false,
171
			JETPACK__VERSION .
172
			'-201243242'
173
		);
174
		wp_style_add_data( 'jetpack-jitm-css', 'rtl', 'replace' );
175
		wp_style_add_data( 'jetpack-jitm-css', 'suffix', $min );
176
		wp_enqueue_style( 'jetpack-jitm-css' );
177
178
		wp_enqueue_script(
179
			'jetpack-jitm-new',
180
			Jetpack::get_file_url_for_environment( '_inc/build/jetpack-jitm.min.js', '_inc/jetpack-jitm.js' ),
181
			array( 'jquery' ),
182
			JETPACK__VERSION,
183
			true
184
		);
185
		wp_localize_script( 'jetpack-jitm-new', 'jitm_config', array(
186
			'api_root'               => esc_url_raw( rest_url() ),
187
			'activate_module_text'   => esc_html__( 'Activate', 'jetpack' ),
188
			'activated_module_text'  => esc_html__( 'Activated', 'jetpack' ),
189
			'activating_module_text' => esc_html__( 'Activating', 'jetpack' ),
190
		) );
191
	}
192
193
	/**
194
	 * Dismisses a JITM feature class so that it will no longer be shown
195
	 *
196
	 * @param $id string The id of the JITM that was dismissed
197
	 * @param $feature_class string The feature class of the JITM that was dismissed
198
	 *
199
	 * @return bool Always true
200
	 */
201
	function dismiss( $id, $feature_class ) {
202
		JetpackTracking::record_user_event( 'jitm_dismiss_client', array(
203
			'jitm_id' => $id,
204
			'feature_class' => $feature_class,
205
		) );
206
207
208
		$hide_jitm = Jetpack_Options::get_option( 'hide_jitm' );
209
		if ( ! is_array( $hide_jitm ) ) {
210
			$hide_jitm = array();
211
		}
212
213
		if ( isset( $hide_jitm[ $feature_class ] ) ) {
214
			if ( ! is_array( $hide_jitm[ $feature_class ] ) ) {
215
				$hide_jitm[ $feature_class ] = array( 'last_dismissal' => 0, 'number' => 0 );
216
			}
217
		} else {
218
			$hide_jitm[ $feature_class ] = array( 'last_dismissal' => 0, 'number' => 0 );
219
		}
220
221
		$number = $hide_jitm[ $feature_class ]['number'];
222
223
		$hide_jitm[ $feature_class ] = array( 'last_dismissal' => time(), 'number' => $number + 1 );
224
225
		Jetpack_Options::update_option( 'hide_jitm', $hide_jitm );
226
227
		return true;
228
	}
229
230
	/**
231
	 * Asks the wpcom API for the current message to display keyed on query string and message path
232
	 *
233
	 * @param $message_path string The message path to ask for
234
	 * @param $query string The query string originally from the front end
235
	 *
236
	 * @return array The JITM's to show, or an empty array if there is nothing to show
237
	 */
238
	function get_messages( $message_path, $query ) {
239
		// custom filters go here
240
		add_filter( 'jitm_woocommerce_services_msg', array( 'Jetpack_JITM', 'jitm_woocommerce_services_msg' ) );
241
		add_filter( 'jitm_jetpack_woo_services_install', array( 'Jetpack_JITM', 'jitm_jetpack_woo_services_install' ) );
242
		add_filter( 'jitm_jetpack_woo_services_activate', array(
243
			'Jetpack_JITM',
244
			'jitm_jetpack_woo_services_activate'
245
		) );
246
247
		$user = wp_get_current_user();
248
249
		// unauthenticated or invalid requests just bail
250
		if ( ! $user ) {
251
			return array();
252
		}
253
254
		require_once( JETPACK__PLUGIN_DIR . 'class.jetpack-client.php' );
255
256
		$site_id = Jetpack_Options::get_option( 'id' );
257
258
		// build our jitm request
259
		$path = add_query_arg( array(
260
			'external_user_id' => urlencode_deep( $user->ID ),
261
			'query_string'     => urlencode_deep( $query ),
262
			'mobile_browser'   => jetpack_is_mobile( 'smart' ) ? 1 : 0,
263
			'_locale'          => get_user_locale(),
264
		), sprintf( '/sites/%d/jitm/%s', $site_id, $message_path ) );
265
266
		// attempt to get from cache
267
		$envelopes = get_transient( 'jetpack_jitm_' . substr( md5( $path ), 0, 31 ) );
268
269
		// if something is in the cache and it was put in the cache after the last sync we care about, use it
270
		$use_cache = false;
271
272
		/** This filter is documented in class.jetpack.php */
273
		if ( apply_filters( 'jetpack_just_in_time_msg_cache', false ) ) {
274
			$use_cache = true;
275
		}
276
277
		if ( $use_cache ) {
278
			$last_sync  = (int) get_transient( 'jetpack_last_plugin_sync' );
279
			$from_cache = $envelopes && $last_sync > 0 && $last_sync < $envelopes['last_response_time'];
280
		} else {
281
			$from_cache = false;
282
		}
283
284
		// otherwise, ask again
285
		if ( ! $from_cache ) {
286
			$wpcom_response = Jetpack_Client::wpcom_json_api_request_as_blog(
287
				$path,
288
				'2',
289
				array(
290
					'user_id'    => $user->ID,
291
					'user_roles' => implode( ',', $user->roles ),
292
				),
293
				null,
294
				'wpcom'
295
			);
296
297
			// silently fail...might be helpful to track it?
298
			if ( is_wp_error( $wpcom_response ) ) {
299
				return array();
300
			}
301
302
			$envelopes = json_decode( $wpcom_response['body'] );
303
304
			if ( ! is_array( $envelopes ) ) {
305
				return array();
306
			}
307
308
			$expiration = isset( $envelopes[0] ) ? $envelopes[0]->ttl : 300;
309
310
			// do not cache if expiration is 0 or we're not using the cache
311
			if ( 0 != $expiration && $use_cache ) {
312
				$envelopes['last_response_time'] = time();
313
314
				set_transient( 'jetpack_jitm_' . substr( md5( $path ), 0, 31 ), $envelopes, $expiration );
315
			}
316
		}
317
318
		$hidden_jitms = Jetpack_Options::get_option( 'hide_jitm' );
319
		unset( $envelopes['last_response_time'] );
320
321
		/**
322
		 * Allow adding your own custom JITMs after a set of JITMs has been received.
323
		 *
324
		 * @since 6.9.0
325
		 *
326
		 * @param array $envelopes array of existing JITMs.
327
		 */
328
		$envelopes = apply_filters( 'jetpack_jitm_received_envelopes', $envelopes );
329
330
		foreach ( $envelopes as $idx => &$envelope ) {
331
332
			$dismissed_feature = isset( $hidden_jitms[ $envelope->feature_class ] ) && is_array( $hidden_jitms[ $envelope->feature_class ] ) ? $hidden_jitms[ $envelope->feature_class ] : null;
333
334
			// if the this feature class has been dismissed and the request has not passed the ttl, skip it as it's been dismissed
335
			if ( is_array( $dismissed_feature ) && ( time() - $dismissed_feature['last_dismissal'] < $envelope->expires || $dismissed_feature['number'] >= $envelope->max_dismissal ) ) {
336
				unset( $envelopes[ $idx ] );
337
				continue;
338
			}
339
340
			JetpackTracking::record_user_event( 'jitm_view_client', array(
341
				'jitm_id' => $envelope->id,
342
			) );
343
344
			$normalized_site_url = Jetpack::build_raw_urls( get_home_url() );
345
346
			$url_params = array(
347
				'source' => "jitm-$envelope->id",
348
				'site' => $normalized_site_url,
349
				'u' => $user->ID,
350
			);
351
352
			if ( ! class_exists( 'Jetpack_Affiliate' ) ) {
353
				require_once JETPACK__PLUGIN_DIR . 'class.jetpack-affiliate.php';
354
			}
355
			// Get affiliate code and add it to the array of URL parameters
356
			if ( '' !== ( $aff = Jetpack_Affiliate::init()->get_affiliate_code() ) ) {
357
				$url_params['aff'] = $aff;
358
			}
359
360
			$envelope->url = add_query_arg( $url_params, 'https://jetpack.com/redirect/' );
361
362
			$envelope->jitm_stats_url = Jetpack::build_stats_url( array( 'x_jetpack-jitm' => $envelope->id ) );
363
364
			if ( $envelope->CTA->hook ) {
365
				$envelope->url = apply_filters( 'jitm_' . $envelope->CTA->hook, $envelope->url );
366
				unset( $envelope->CTA->hook );
367
			}
368
369
			if ( isset( $envelope->content->hook ) ) {
370
				$envelope->content = apply_filters( 'jitm_' . $envelope->content->hook, $envelope->content );
371
				unset( $envelope->content->hook );
372
			}
373
374
			// no point in showing an empty message
375
			if ( empty( $envelope->content->message ) ) {
376
				unset( $envelopes[ $idx ] );
377
				continue;
378
			}
379
380
			switch ( $envelope->content->icon ) {
381
				case 'jetpack':
382
					$envelope->content->icon = '<div class="jp-emblem">' . Jetpack::get_jp_emblem() . '</div>';
383
					break;
384
				case 'woocommerce':
385
					$envelope->content->icon = '<div class="jp-emblem"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Layer_1" x="0px" y="0px" viewBox="0 0 168 100" xml:space="preserve" enable-background="new 0 0 168 100" width="50" height="30"><style type="text/css">
386
					.st0{clip-path:url(#SVGID_2_);enable-background:new    ;}
387
					.st1{clip-path:url(#SVGID_4_);}
388
					.st2{clip-path:url(#SVGID_6_);}
389
					.st3{clip-path:url(#SVGID_8_);fill:#8F567F;}
390
					.st4{clip-path:url(#SVGID_10_);fill:#FFFFFE;}
391
					.st5{clip-path:url(#SVGID_12_);fill:#FFFFFE;}
392
					.st6{clip-path:url(#SVGID_14_);fill:#FFFFFE;}
393
				</style><g><defs><polygon id="SVGID_1_" points="83.8 100 0 100 0 0.3 83.8 0.3 167.6 0.3 167.6 100 "/></defs><clipPath id="SVGID_2_"><use xlink:href="#SVGID_1_" overflow="visible"/></clipPath><g class="st0"><g><defs><rect id="SVGID_3_" width="168" height="100"/></defs><clipPath id="SVGID_4_"><use xlink:href="#SVGID_3_" overflow="visible"/></clipPath><g class="st1"><defs><path id="SVGID_5_" d="M15.6 0.3H152c8.6 0 15.6 7 15.6 15.6v52c0 8.6-7 15.6-15.6 15.6h-48.9l6.7 16.4L80.2 83.6H15.6C7 83.6 0 76.6 0 67.9v-52C0 7.3 7 0.3 15.6 0.3"/></defs><clipPath id="SVGID_6_"><use xlink:href="#SVGID_5_" overflow="visible"/></clipPath><g class="st2"><defs><rect id="SVGID_7_" width="168" height="100"/></defs><clipPath id="SVGID_8_"><use xlink:href="#SVGID_7_" overflow="visible"/></clipPath><rect x="-10" y="-9.7" class="st3" width="187.6" height="119.7"/></g></g></g></g></g><g><defs><path id="SVGID_9_" d="M8.4 14.5c1-1.3 2.4-2 4.3-2.1 3.5-0.2 5.5 1.4 6 4.9 2.1 14.3 4.4 26.4 6.9 36.4l15-28.6c1.4-2.6 3.1-3.9 5.2-4.1 3-0.2 4.9 1.7 5.6 5.7 1.7 9.1 3.9 16.9 6.5 23.4 1.8-17.4 4.8-30 9-37.7 1-1.9 2.5-2.9 4.5-3 1.6-0.1 3 0.3 4.3 1.4 1.3 1 2 2.3 2.1 3.9 0.1 1.2-0.1 2.3-0.7 3.3 -2.7 5-4.9 13.2-6.6 24.7 -1.7 11.1-2.3 19.8-1.9 26.1 0.1 1.7-0.1 3.2-0.8 4.5 -0.8 1.5-2 2.4-3.7 2.5 -1.8 0.1-3.6-0.7-5.4-2.5C52.4 66.7 47.4 57 43.7 44.1c-4.4 8.8-7.7 15.3-9.9 19.7 -4 7.7-7.5 11.7-10.3 11.9 -1.9 0.1-3.5-1.4-4.8-4.7 -3.5-9-7.3-26.3-11.3-52C7.1 17.3 7.5 15.8 8.4 14.5"/></defs><clipPath id="SVGID_10_"><use xlink:href="#SVGID_9_" overflow="visible"/></clipPath><rect x="-2.7" y="-0.6" class="st4" width="90.6" height="86.4"/></g><g><defs><path id="SVGID_11_" d="M155.6 25.2c-2.5-4.3-6.1-6.9-11-7.9 -1.3-0.3-2.5-0.4-3.7-0.4 -6.6 0-11.9 3.4-16.1 10.2 -3.6 5.8-5.3 12.3-5.3 19.3 0 5.3 1.1 9.8 3.3 13.6 2.5 4.3 6.1 6.9 11 7.9 1.3 0.3 2.5 0.4 3.7 0.4 6.6 0 12-3.4 16.1-10.2 3.6-5.9 5.3-12.4 5.3-19.4C159 33.4 157.9 28.9 155.6 25.2zM147 44.2c-0.9 4.5-2.7 7.9-5.2 10.1 -2 1.8-3.9 2.5-5.5 2.2 -1.7-0.3-3-1.8-4-4.4 -0.8-2.1-1.2-4.2-1.2-6.2 0-1.7 0.2-3.4 0.5-5 0.6-2.8 1.8-5.5 3.6-8.1 2.3-3.3 4.7-4.8 7.1-4.2 1.7 0.3 3 1.8 4 4.4 0.8 2.1 1.2 4.2 1.2 6.2C147.5 40.9 147.3 42.6 147 44.2z"/></defs><clipPath id="SVGID_12_"><use xlink:href="#SVGID_11_" overflow="visible"/></clipPath><rect x="109.6" y="6.9" class="st5" width="59.4" height="71.4"/></g><g><defs><path id="SVGID_13_" d="M112.7 25.2c-2.5-4.3-6.1-6.9-11-7.9 -1.3-0.3-2.5-0.4-3.7-0.4 -6.6 0-11.9 3.4-16.1 10.2 -3.5 5.8-5.3 12.3-5.3 19.3 0 5.3 1.1 9.8 3.3 13.6 2.5 4.3 6.1 6.9 11 7.9 1.3 0.3 2.5 0.4 3.7 0.4 6.6 0 12-3.4 16.1-10.2 3.5-5.9 5.3-12.4 5.3-19.4C116 33.4 114.9 28.9 112.7 25.2zM104.1 44.2c-0.9 4.5-2.7 7.9-5.2 10.1 -2 1.8-3.9 2.5-5.5 2.2 -1.7-0.3-3-1.8-4-4.4 -0.8-2.1-1.2-4.2-1.2-6.2 0-1.7 0.2-3.4 0.5-5 0.6-2.8 1.8-5.5 3.6-8.1 2.3-3.3 4.7-4.8 7.1-4.2 1.7 0.3 3 1.8 4 4.4 0.8 2.1 1.2 4.2 1.2 6.2C104.6 40.9 104.4 42.6 104.1 44.2z"/></defs><clipPath id="SVGID_14_"><use xlink:href="#SVGID_13_" overflow="visible"/></clipPath><rect x="66.7" y="6.9" class="st6" width="59.4" height="71.4"/></g></svg></div>';
394
					break;
395
				default:
396
					$envelope->content->icon = '';
397
					break;
398
			}
399
400
			$jetpack = Jetpack::init();
401
			$jetpack->stat( 'jitm', $envelope->id . '-viewed-' . JETPACK__VERSION );
402
			$jetpack->do_stats( 'server_side' );
403
		}
404
405
		return $envelopes;
406
	}
407
}
408
409
add_action( 'admin_init', array( 'Jetpack_JITM', 'init' ) );
410