PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.2
Jetpack – WP Security, Backup, Speed, & Growth v16.2
16.3-a.5 16.3-a.7 16.3-a.3 16.3-a.1 16.2 16.2-beta 12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 All 506 releases
jetpack / jetpack_vendor / automattic / jetpack-jitm / src / class-post-connection-jitm.php

class-post-connection-jitm.php in Jetpack – WP Security, Backup, Speed, & Growth 16.2, at jetpack_vendor/automattic/jetpack-jitm/src/class-post-connection-jitm.php

435 lines 12.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Jetpack's Post-Connection JITM class.
4 *
5 * @package automattic/jetpack-jitm
6 */
7
8 namespace Automattic\Jetpack\JITMS;
9
10 use Automattic\Jetpack\A8c_Mc_Stats;
11 use Automattic\Jetpack\Connection\Client;
12 use Automattic\Jetpack\Connection\Manager;
13 use Automattic\Jetpack\Device_Detection;
14 use Automattic\Jetpack\Partner;
15 use Automattic\Jetpack\Redirect;
16 use Automattic\Jetpack\Tracking;
17
18 if ( ! defined( 'ABSPATH' ) ) {
19 exit( 0 );
20 }
21
22 /**
23 * Jetpack just in time messaging through out the admin
24 *
25 * @since 1.1.0
26 *
27 * @since-jetpack 5.6.0
28 */
29 class Post_Connection_JITM extends JITM {
30
31 /**
32 * Tracking object.
33 *
34 * @var \Automattic\Jetpack\Tracking
35 *
36 * @access private
37 */
38 public $tracking;
39
40 /**
41 * JITM constructor.
42 */
43 public function __construct() {
44 $this->tracking = new Tracking();
45 }
46
47 /**
48 * A special filter for WooCommerce, to set a message based on local state.
49 *
50 * @param object $content The current message.
51 *
52 * @return object The new message.
53 */
54 public static function jitm_woocommerce_services_msg( $content ) {
55 if ( ! function_exists( 'wc_get_base_location' ) ) {
56 return $content;
57 }
58
59 $base_location = wc_get_base_location();
60
61 switch ( $base_location['country'] ) {
62 case 'US':
63 $content->message = esc_html__( 'New free service: Show USPS shipping rates on your store! Added bonus: print shipping labels without leaving WooCommerce.', 'jetpack-jitm' );
64 break;
65 case 'CA':
66 $content->message = esc_html__( 'New free service: Show Canada Post shipping rates on your store!', 'jetpack-jitm' );
67 break;
68 default:
69 $content->message = '';
70 }
71
72 return $content;
73 }
74
75 /**
76 * A special filter for WooCommerce Call To Action button
77 *
78 * @return string The new CTA
79 */
80 public static function jitm_jetpack_woo_services_install() {
81 return wp_nonce_url(
82 add_query_arg(
83 array(
84 'wc-services-action' => 'install',
85 ),
86 admin_url( 'admin.php?page=wc-settings' )
87 ),
88 'wc-services-install'
89 );
90 }
91
92 /**
93 * A special filter for WooCommerce Call To Action button.
94 *
95 * @return string The new CTA
96 */
97 public static function jitm_jetpack_woo_services_activate() {
98 return wp_nonce_url(
99 add_query_arg(
100 array(
101 'wc-services-action' => 'activate',
102 ),
103 admin_url( 'admin.php?page=wc-settings' )
104 ),
105 'wc-services-install'
106 );
107 }
108
109 /**
110 * A special filter used in the CTA of a JITM offering to install the Creative Mail plugin.
111 *
112 * @return string The new CTA
113 */
114 public static function jitm_jetpack_creative_mail_install() {
115 return wp_nonce_url(
116 add_query_arg(
117 array(
118 'creative-mail-action' => 'install',
119 ),
120 admin_url( 'admin.php?page=jetpack-forms-admin' )
121 ),
122 'creative-mail-install'
123 );
124 }
125
126 /**
127 * A special filter used in the CTA of a JITM offering to activate the Creative Mail plugin.
128 *
129 * @return string The new CTA
130 */
131 public static function jitm_jetpack_creative_mail_activate() {
132 return wp_nonce_url(
133 add_query_arg(
134 array(
135 'creative-mail-action' => 'activate',
136 ),
137 admin_url( 'admin.php?page=jetpack-forms-admin' )
138 ),
139 'creative-mail-install'
140 );
141 }
142
143 /**
144 * A special filter used in the CTA of a JITM offering to install the Jetpack Backup plugin.
145 *
146 * @return string The new CTA
147 */
148 public static function jitm_jetpack_backup_install() {
149 return wp_nonce_url(
150 add_query_arg(
151 array(
152 'jetpack-backup-action' => 'install',
153 ),
154 admin_url( 'admin.php?page=jetpack' )
155 ),
156 'jetpack-backup-install'
157 );
158 }
159
160 /**
161 * A special filter used in the CTA of a JITM offering to activate the Jetpack Backup plugin.
162 *
163 * @return string The new CTA
164 */
165 public static function jitm_jetpack_backup_activate() {
166 return wp_nonce_url(
167 add_query_arg(
168 array(
169 'jetpack-backup-action' => 'activate',
170 ),
171 admin_url( 'admin.php?page=jetpack' )
172 ),
173 'jetpack-backup-install'
174 );
175 }
176
177 /**
178 * A special filter used in the CTA of a JITM offering to install the Jetpack Boost plugin.
179 *
180 * @return string The new CTA
181 */
182 public static function jitm_jetpack_boost_install() {
183 return wp_nonce_url(
184 add_query_arg(
185 array(
186 'jetpack-boost-action' => 'install',
187 ),
188 admin_url( 'admin.php?page=jetpack' )
189 ),
190 'jetpack-boost-install'
191 );
192 }
193
194 /**
195 * A special filter used in the CTA of a JITM offering to activate the Jetpack Boost plugin.
196 *
197 * @return string The new CTA
198 */
199 public static function jitm_jetpack_boost_activate() {
200 return wp_nonce_url(
201 add_query_arg(
202 array(
203 'jetpack-boost-action' => 'activate',
204 ),
205 admin_url( 'admin.php?page=jetpack' )
206 ),
207 'jetpack-boost-install'
208 );
209 }
210
211 /**
212 * Dismisses a JITM feature class so that it will no longer be shown.
213 *
214 * @param string $id The id of the JITM that was dismissed.
215 * @param string $feature_class The feature class of the JITM that was dismissed.
216 *
217 * @return bool Always true.
218 */
219 public function dismiss( $id, $feature_class ) {
220 $this->tracking->record_user_event(
221 'jitm_dismiss_client',
222 array(
223 'jitm_id' => $id,
224 'feature_class' => $feature_class,
225 )
226 );
227 $this->save_dismiss( $feature_class );
228 return true;
229 }
230
231 /**
232 * Asks the wpcom API for the current message to display keyed on query string and message path.
233 *
234 * For sites running on the Dotcom Simple codebase, the network request is bypassed
235 * via Client::wpcom_json_api_request_as_blog allowing for the JITM\Engine to be called
236 * directly.
237 *
238 * @param string $message_path The message path to ask for.
239 * @param array $query Query parameters as an associative array.
240 * @param bool $full_jp_logo_exists If there is a full Jetpack logo already on the page.
241 *
242 * @return array The JITM's to show, or an empty array if there is nothing to show
243 */
244 public function get_messages( $message_path, $query, $full_jp_logo_exists ) {
245 // WooCommerce Services.
246 add_filter( 'jitm_woocommerce_services_msg', array( $this, 'jitm_woocommerce_services_msg' ) );
247 add_filter( 'jitm_jetpack_woo_services_install', array( $this, 'jitm_jetpack_woo_services_install' ) );
248 add_filter( 'jitm_jetpack_woo_services_activate', array( $this, 'jitm_jetpack_woo_services_activate' ) );
249
250 // Creative Mail.
251 add_filter( 'jitm_jetpack_creative_mail_install', array( $this, 'jitm_jetpack_creative_mail_install' ) );
252 add_filter( 'jitm_jetpack_creative_mail_activate', array( $this, 'jitm_jetpack_creative_mail_activate' ) );
253
254 // Jetpack Backup.
255 add_filter( 'jitm_jetpack_backup_install', array( $this, 'jitm_jetpack_backup_install' ) );
256 add_filter( 'jitm_jetpack_backup_activate', array( $this, 'jitm_jetpack_backup_activate' ) );
257
258 // Jetpack Boost.
259 add_filter( 'jitm_jetpack_boost_install', array( $this, 'jitm_jetpack_boost_install' ) );
260 add_filter( 'jitm_jetpack_boost_activate', array( $this, 'jitm_jetpack_boost_activate' ) );
261
262 $user = wp_get_current_user();
263
264 // Unauthenticated or invalid requests just bail.
265 if ( ! $user ) {
266 return array();
267 }
268
269 $user_roles = implode( ',', $user->roles );
270 $site_id = \Jetpack_Options::get_option( 'id' );
271
272 // Build our jitm request.
273 $path = add_query_arg(
274 array(
275 'external_user_id' => urlencode_deep( $user->ID ),
276 'user_roles' => urlencode_deep( $user_roles ),
277 'query_string' => urlencode_deep( build_query( $query ) ),
278 'mobile_browser' => Device_Detection::is_smartphone() ? 1 : 0,
279 '_locale' => get_user_locale(),
280 ),
281 sprintf( '/sites/%d/jitm/%s', $site_id, $message_path )
282 );
283
284 $cache_key = 'jetpack_jitm_' . substr( md5( $path ), 0, 31 );
285
286 // Attempt to get from cache.
287 $envelopes = get_transient( $cache_key );
288
289 // If something is in the cache and it was put in the cache after the last sync we care about, use it.
290 $use_cache = false;
291
292 /**
293 * Filter to turn off jitm caching
294 *
295 * @since 1.1.0
296 * @since-jetpack 5.4.0
297 *
298 * @param bool true Whether to cache just in time messages
299 */
300 if ( apply_filters( 'jetpack_just_in_time_msg_cache', true ) ) {
301 $use_cache = true;
302 }
303
304 if ( $use_cache ) {
305 $last_sync = (int) get_transient( 'jetpack_last_plugin_sync' );
306 // The sync timestamp indicates when a plugin change was last sent to Jetpack, however,
307 // it's stored in a transient and doesn't stay forever. Therefore, an admin who last changed
308 // a plugin a month ago is likely to have $last_sync=0.
309 //
310 // If the sync timestamp is missing (value 0): use the cache.
311 // If the timestamp exists and is older than the cached envelope: use the cache.
312 // If the timestamp exists and is newer: bypass and refresh.
313 // (This case means the JITM was created before the last plugin activate/deactivate and is invalid).
314 $from_cache = $envelopes && ( 0 === $last_sync || $last_sync < $envelopes['last_response_time'] );
315 } else {
316 $from_cache = false;
317 }
318
319 // Otherwise, ask again.
320 if ( ! $from_cache ) {
321 $wpcom_response = Client::wpcom_json_api_request_as_blog(
322 $path,
323 '2',
324 array(
325 'user_id' => $user->ID,
326 'user_roles' => implode( ',', $user->roles ),
327 ),
328 null,
329 'wpcom'
330 );
331
332 // silently fail...might be helpful to track it?
333 if ( is_wp_error( $wpcom_response ) ) {
334 return array();
335 }
336
337 $envelopes = json_decode( $wpcom_response['body'] );
338
339 if ( ! is_array( $envelopes ) ) {
340 return array();
341 }
342
343 $expiration = isset( $envelopes[0] ) ? $envelopes[0]->ttl : 300;
344
345 // Do not cache if expiration is 0 or we're not using the cache.
346 if ( 0 !== $expiration && $use_cache ) {
347 $envelopes['last_response_time'] = time();
348 set_transient( $cache_key, $envelopes, $expiration );
349 }
350 }
351
352 $hidden_jitms = \Jetpack_Options::get_option( 'hide_jitm' );
353 unset( $envelopes['last_response_time'] );
354
355 /**
356 * Allow adding your own custom JITMs after a set of JITMs has been received.
357 *
358 * @since 1.1.0
359 * @since-jetpack 6.9.0
360 * @since-jetpack 8.3.0 - Added Message path.
361 *
362 * @param array $envelopes array of existing JITMs.
363 * @param string $message_path The message path to ask for.
364 */
365 $envelopes = apply_filters( 'jetpack_jitm_received_envelopes', $envelopes, $message_path );
366
367 foreach ( $envelopes as $idx => &$envelope ) {
368
369 $dismissed_feature = isset( $hidden_jitms[ $envelope->feature_class ] ) && is_array( $hidden_jitms[ $envelope->feature_class ] ) ? $hidden_jitms[ $envelope->feature_class ] : null;
370
371 // If the this feature class has been dismissed and the request has not passed the ttl, skip it as it's been dismissed.
372 if ( is_array( $dismissed_feature ) && ( time() - $dismissed_feature['last_dismissal'] < $envelope->expires || $dismissed_feature['number'] >= $envelope->max_dismissal ) ) {
373 unset( $envelopes[ $idx ] );
374 continue;
375 }
376
377 $this->tracking->record_user_event(
378 'jitm_view_client',
379 array(
380 'jitm_id' => $envelope->id,
381 'jitm_message_path' => $message_path,
382 )
383 );
384
385 $url_params = array(
386 'u' => $user->ID,
387 );
388
389 // Get affiliate code and add it to the array of URL parameters.
390 $aff = Partner::init()->get_partner_code( Partner::AFFILIATE_CODE );
391 if ( '' !== $aff ) {
392 $url_params['aff'] = $aff;
393 }
394
395 // Check if the current user has connected their WP.com account
396 // and if not add this information to the the array of URL parameters.
397 if ( ! ( new Manager() )->is_user_connected( $user->ID ) ) {
398 $url_params['query'] = 'unlinked=1';
399 }
400 $envelope->url = esc_url( Redirect::get_url( "jitm-$envelope->id", $url_params ) );
401
402 $stats = new A8c_Mc_Stats();
403
404 $envelope->jitm_stats_url = $stats->build_stats_url( array( 'x_jetpack-jitm' => $envelope->id ) );
405
406 // phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
407 // $CTA is not valid per PHPCS, but it is part of the return from WordPress.com, so allowing.
408 if ( $envelope->CTA->hook ) {
409 $envelope->url = apply_filters( 'jitm_' . $envelope->CTA->hook, $envelope->url );
410 unset( $envelope->CTA->hook );
411 }
412 // phpcs:enable
413
414 if ( isset( $envelope->content->hook ) ) {
415 $envelope->content = apply_filters( 'jitm_' . $envelope->content->hook, $envelope->content );
416 unset( $envelope->content->hook );
417 }
418
419 // No point in showing an empty message.
420 if ( empty( $envelope->content->message ) ) {
421 unset( $envelopes[ $idx ] );
422 continue;
423 }
424
425 $envelope->content->icon = $this->generate_icon( $envelope->content->icon, $full_jp_logo_exists );
426 $envelope->message_path = esc_attr( $message_path );
427
428 $stats->add( 'jitm', $envelope->id . '-viewed' );
429 $stats->do_server_side_stats();
430 }
431
432 return $envelopes;
433 }
434 }
435