Brak opisu

class.jetpack-connection-banner.php 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550
  1. <?php
  2. use Automattic\Jetpack\Assets;
  3. use Automattic\Jetpack\Assets\Logo;
  4. use Automattic\Jetpack\Constants;
  5. use Automattic\Jetpack\Device_Detection\User_Agent_Info;
  6. use Automattic\Jetpack\Licensing;
  7. use Automattic\Jetpack\Redirect;
  8. class Jetpack_Connection_Banner {
  9. /**
  10. * @var Jetpack_Connection_Banner
  11. **/
  12. private static $instance = null;
  13. static function init() {
  14. if ( is_null( self::$instance ) ) {
  15. self::$instance = new Jetpack_Connection_Banner();
  16. }
  17. return self::$instance;
  18. }
  19. /**
  20. * Jetpack_Connection_Banner constructor.
  21. *
  22. * Since we call the Jetpack_Connection_Banner:init() method from the `Jetpack` class, and after
  23. * the admin_init action fires, we know that the admin is initialized at this point.
  24. */
  25. private function __construct() {
  26. add_action( 'current_screen', array( $this, 'maybe_initialize_hooks' ) );
  27. }
  28. /**
  29. * The banner is forcibly displayed.
  30. *
  31. * @return bool
  32. */
  33. public static function force_display() {
  34. /**
  35. * This is an experiment for partners to test. Allow customization of the behavior of pre-connection banners.
  36. *
  37. * @since 8.6.0
  38. *
  39. * @param bool $always_show_prompt Should this prompt always appear? Default to false.
  40. */
  41. return apply_filters( 'jetpack_pre_connection_prompt_helpers', false );
  42. }
  43. /**
  44. * Can the banner be displayed for the given screen?
  45. *
  46. * @param \WP_Screen $current_screen Current WordPress screen.
  47. *
  48. * @return bool
  49. */
  50. public static function can_be_displayed( $current_screen ) {
  51. $has_connected_owner = Jetpack::connection()->has_connected_owner();
  52. $is_connected = Jetpack::is_connection_ready();
  53. $has_licenses = ! empty( Licensing::instance()->stored_licenses() );
  54. // Don't show the connect notice if the site has a connected owner.
  55. if ( $has_connected_owner ) {
  56. return false;
  57. }
  58. // Don't show the connect notice if a site connection is established and there are no stored licenses.
  59. // Stored licenses indicate that a purchased product may not be provisioned yet hence we need to keep
  60. // showing the notice to nudge the user to connect in order to have their product(s) provisioned.
  61. if ( $is_connected && ! $has_licenses ) {
  62. return false;
  63. }
  64. // Kill if banner has been dismissed and the pre-connection helpers filter is not set.
  65. if (
  66. Jetpack_Options::get_option( 'dismissed_connection_banner' ) &&
  67. ! self::force_display()
  68. ) {
  69. return false;
  70. }
  71. // Don't show the connect notice anywhere but the plugins.php after activating.
  72. if ( 'plugins' !== $current_screen->base && 'dashboard' !== $current_screen->base ) {
  73. return false;
  74. }
  75. if ( ! current_user_can( 'jetpack_connect' ) ) {
  76. return false;
  77. }
  78. return true;
  79. }
  80. /**
  81. * Given a string for the the banner was added, and an int that represents the slide to
  82. * a URL for, this function returns a connection URL with a from parameter that will
  83. * support split testing.
  84. *
  85. * @since 7.2 Event key format is now banner-connect-banner-72-dashboard or connect-banner-72-plugins.
  86. * The param $slide_num was removed since we removed all slides but the first one.
  87. * @since 4.4.0
  88. *
  89. * @param string $jp_version_banner_added A short version of when the banner was added. Ex. 44
  90. *
  91. * @return string
  92. */
  93. function build_connect_url_for_slide( $jp_version_banner_added ) {
  94. global $current_screen;
  95. $url = Jetpack::init()->build_connect_url(
  96. true,
  97. false,
  98. sprintf( 'connect-banner-%s-%s', $jp_version_banner_added, $current_screen->base )
  99. );
  100. return add_query_arg( 'auth_approved', 'true', $url );
  101. }
  102. /**
  103. * Will initialize hooks to display the new (as of 4.4) connection banner if the current user can
  104. * connect Jetpack, if Jetpack has not been deactivated, and if the current page is the plugins page.
  105. *
  106. * @since 4.4.0
  107. * @since 4.5.0 Made the new (as of 4.4) connection banner display to everyone by default.
  108. * @since 5.3.0 Running another split test between 4.4 banner and a new one in 5.3.
  109. * @since 7.2 B test was removed.
  110. * @since 9.7 Moved the connection condition checking to this method to fulfill Licensing requirements.
  111. *
  112. * @param $current_screen
  113. */
  114. function maybe_initialize_hooks( $current_screen ) {
  115. if ( ! self::can_be_displayed( $current_screen ) ) {
  116. return;
  117. }
  118. if ( ! empty( Licensing::instance()->stored_licenses() ) ) {
  119. add_action( 'admin_notices', array( $this, 'render_license_aware_banner' ) );
  120. } else {
  121. add_action( 'admin_notices', array( $this, 'render_banner' ) );
  122. }
  123. add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_banner_scripts' ) );
  124. add_action( 'admin_print_styles', array( Jetpack::init(), 'admin_banner_styles' ) );
  125. if ( Jetpack::state( 'network_nag' ) ) {
  126. add_action( 'network_admin_notices', array( $this, 'network_connect_notice' ) );
  127. }
  128. // Only fires immediately after plugin activation
  129. if ( get_transient( 'activated_jetpack' ) ) {
  130. add_action( 'admin_notices', array( $this, 'render_connect_prompt_full_screen' ) );
  131. delete_transient( 'activated_jetpack' );
  132. }
  133. }
  134. /**
  135. * Enqueues JavaScript for new connection banner.
  136. *
  137. * @since 4.4.0
  138. */
  139. public static function enqueue_banner_scripts() {
  140. wp_enqueue_script(
  141. 'jetpack-connection-banner-js',
  142. Assets::get_file_url_for_environment(
  143. '_inc/build/jetpack-connection-banner.min.js',
  144. '_inc/jetpack-connection-banner.js'
  145. ),
  146. array( 'jquery' ),
  147. JETPACK__VERSION,
  148. true
  149. );
  150. wp_localize_script(
  151. 'jetpack-connection-banner-js',
  152. 'jp_banner',
  153. array(
  154. 'ajax_url' => admin_url( 'admin-ajax.php' ),
  155. 'connectionBannerNonce' => wp_create_nonce( 'jp-connection-banner-nonce' ),
  156. )
  157. );
  158. }
  159. /**
  160. * Enqueues JavaScript and CSS for new connect-in-place flow.
  161. *
  162. * @since 7.7
  163. */
  164. public static function enqueue_connect_button_scripts() {
  165. global $is_safari;
  166. wp_enqueue_script(
  167. 'jetpack-connect-button',
  168. Assets::get_file_url_for_environment(
  169. '_inc/build/connect-button.min.js',
  170. '_inc/connect-button.js'
  171. ),
  172. array( 'jquery' ),
  173. JETPACK__VERSION,
  174. true
  175. );
  176. wp_enqueue_style(
  177. 'jetpack-connect-button',
  178. Assets::get_file_url_for_environment(
  179. 'css/jetpack-connect.min.css',
  180. 'css/jetpack-connect.css'
  181. )
  182. );
  183. $jetpackApiUrl = wp_parse_url( Jetpack::connection()->api_url( '' ) );
  184. // Due to the limitation in how 3rd party cookies are handled in Safari and Opera,
  185. // we're falling back to the original flow.
  186. if ( $is_safari || User_Agent_Info::is_opera_desktop() || Constants::is_true( 'JETPACK_SHOULD_NOT_USE_CONNECTION_IFRAME' ) ) {
  187. $force_variation = 'original';
  188. } else {
  189. $force_variation = 'in_place';
  190. }
  191. $tracking = new Automattic\Jetpack\Tracking();
  192. $identity = $tracking->tracks_get_identity( get_current_user_id() );
  193. wp_localize_script(
  194. 'jetpack-connect-button',
  195. 'jpConnect',
  196. array(
  197. 'apiBaseUrl' => esc_url_raw( rest_url( 'jetpack/v4' ) ),
  198. 'registrationNonce' => wp_create_nonce( 'jetpack-registration-nonce' ),
  199. 'apiNonce' => wp_create_nonce( 'wp_rest' ),
  200. 'apiSiteDataNonce' => wp_create_nonce( 'wp_rest' ),
  201. 'buttonTextRegistering' => __( 'Loading...', 'jetpack' ),
  202. 'jetpackApiDomain' => $jetpackApiUrl['scheme'] . '://' . $jetpackApiUrl['host'],
  203. 'forceVariation' => $force_variation,
  204. 'connectInPlaceUrl' => Jetpack::admin_url( 'page=jetpack#/setup' ),
  205. 'dashboardUrl' => Jetpack::admin_url( 'page=jetpack#/dashboard' ),
  206. 'plansPromptUrl' => Redirect::get_url( 'jetpack-connect-plans' ),
  207. 'identity' => $identity,
  208. 'preFetchScript' => plugins_url( '_inc/build/admin.js', JETPACK__PLUGIN_FILE ) . '?ver=' . JETPACK__VERSION,
  209. )
  210. );
  211. }
  212. /**
  213. * Renders the new connection banner as of 4.4.0.
  214. *
  215. * @since 7.2 Copy and visual elements reduced to show the new focus of Jetpack on Security and Performance.
  216. * @since 4.4.0
  217. */
  218. public function render_banner() {
  219. ?>
  220. <div id="message" class="updated jp-wpcom-connect__container">
  221. <div class="jp-wpcom-connect__container-top-text">
  222. <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><rect x="0" fill="none" width="24" height="24"/><g><path d="M12 2C6.477 2 2 6.477 2 12s4.477 10 10 10 10-4.477 10-10S17.523 2 12 2zm1 15h-2v-2h2v2zm0-4h-2l-.5-6h3l-.5 6z"/></g></svg>
  223. <span>
  224. <?php esc_html_e( 'You’re almost done. Set up Jetpack to enable powerful security and performance tools for WordPress.', 'jetpack' ); ?>
  225. </span>
  226. </div>
  227. <div class="jp-wpcom-connect__inner-container">
  228. <?php
  229. if ( ! $this->force_display() ) :
  230. ?>
  231. <span
  232. class="notice-dismiss connection-banner-dismiss"
  233. title="<?php esc_attr_e( 'Dismiss this notice', 'jetpack' ); ?>">
  234. </span>
  235. <?php
  236. endif;
  237. ?>
  238. <div class="jp-wpcom-connect__content-container">
  239. <!-- slide 1: intro -->
  240. <div class="jp-wpcom-connect__slide jp-wpcom-connect__slide-one jp__slide-is-active">
  241. <div class="jp-wpcom-connect__content-icon jp-connect-illo">
  242. <?php
  243. $logo = new Logo();
  244. echo $logo->render();
  245. ?>
  246. <img
  247. src="<?php echo plugins_url( 'images/jetpack-powering-up.svg', JETPACK__PLUGIN_FILE ); ?>"
  248. class="jp-wpcom-connect__hide-phone-and-smaller"
  249. alt="
  250. <?php
  251. esc_attr_e(
  252. 'Jetpack premium services offer even more powerful performance, security, ' .
  253. 'and revenue tools to help you keep your site safe, fast, and help generate income.',
  254. 'jetpack'
  255. );
  256. ?>
  257. "
  258. height="auto"
  259. width="225"
  260. />
  261. </div>
  262. <div class="jp-wpcom-connect__slide-text">
  263. <h2><?php esc_html_e( 'Simplify your site security and performance with Jetpack', 'jetpack' ); ?></h2>
  264. <p>
  265. <?php
  266. esc_html_e(
  267. 'Jetpack protects you against brute force attacks and unauthorized logins. Basic protection ' .
  268. 'is always free, while premium plans add unlimited backups of your whole site, spam protection, ' .
  269. 'malware scanning, and automated fixes.',
  270. 'jetpack'
  271. );
  272. ?>
  273. </p>
  274. <p>
  275. <?php
  276. esc_html_e(
  277. 'Activate site accelerator tools and watch your page load times decrease—we’ll ' .
  278. 'optimize your images and serve them from our own powerful global network of servers, ' .
  279. 'and speed up your mobile site to reduce bandwidth usage.',
  280. 'jetpack'
  281. );
  282. ?>
  283. </p>
  284. <div class="jp-banner__button-container">
  285. <span class="jp-banner__tos-blurb"><?php jetpack_render_tos_blurb(); ?></span>
  286. <a
  287. href="<?php echo esc_url( $this->build_connect_url_for_slide( '72' ) ); ?>"
  288. class="dops-button is-primary jp-banner__alt-connect-button">
  289. <?php esc_html_e( 'Set up Jetpack', 'jetpack' ); ?>
  290. </a>
  291. </div>
  292. </div>
  293. </div> <!-- end slide 1 -->
  294. </div>
  295. </div>
  296. </div>
  297. <?php
  298. }
  299. /**
  300. * Renders the license-away version of the connection banner.
  301. *
  302. * @since 9.0.0
  303. */
  304. public function render_license_aware_banner() {
  305. ?>
  306. <div id="message" class="updated jp-wpcom-connect__container">
  307. <div class="jp-wpcom-connect__inner-container">
  308. <div class="jp-wpcom-connect__content-container">
  309. <!-- slide 1: intro -->
  310. <div class="jp-wpcom-connect__slide jp-wpcom-connect__slide-one jp__slide-is-active">
  311. <div class="jp-wpcom-connect__content-icon jp-connect-illo">
  312. <?php echo ( new Logo() )->render(); ?>
  313. <img
  314. src="<?php echo esc_url( plugins_url( 'images/jetpack-powering-up.svg', JETPACK__PLUGIN_FILE ) ); ?>"
  315. class="jp-wpcom-connect__hide-phone-and-smaller"
  316. alt="
  317. <?php
  318. esc_attr_e(
  319. 'Jetpack premium services offer even more powerful performance, security, and revenue tools to help you keep your site safe, fast, and help generate income.',
  320. 'jetpack'
  321. );
  322. ?>
  323. "
  324. height="auto"
  325. width="225"
  326. />
  327. </div>
  328. <div class="jp-wpcom-connect__slide-text">
  329. <h2 class="jp-wpcom-connect__quest">
  330. <svg class="gridicon gridicons-notice jp-wpcom-connect__quest-marker" height="38" width="38" viewBox="0 0 24 24">
  331. <g>
  332. <rect x="8" y="6" width="8" height="12" style="fill:#000000" />
  333. <path d="M12 2C6.477 2 2 6.477 2 12s4.477 10 10 10 10-4.477 10-10S17.523 2 12 2zm1 15h-2v-2h2v2zm0-4h-2l-.5-6h3l-.5 6z"></path>
  334. </g>
  335. </svg>
  336. <?php esc_html_e( 'Your Jetpack purchase needs completion! Please set up the plugin for your subscription.', 'jetpack' ); ?>
  337. </h2>
  338. <p>
  339. <?php
  340. esc_html_e(
  341. 'Jetpack offers security, performance, and marketing tools made for WordPress sites by WordPress experts. Set up Jetpack to enable new features for this site; don\'t let your subscription go to waste!',
  342. 'jetpack'
  343. );
  344. ?>
  345. </p>
  346. <div class="jp-banner__button-container">
  347. <span class="jp-banner__tos-blurb"><?php jetpack_render_tos_blurb(); ?></span>
  348. <a
  349. href="<?php echo esc_url( $this->build_connect_url_for_slide( '90' ) ); ?>"
  350. class="dops-button is-primary jp-banner__alt-connect-button">
  351. <?php esc_html_e( 'Set up Jetpack', 'jetpack' ); ?>
  352. </a>
  353. </div>
  354. </div>
  355. </div> <!-- end slide 1 -->
  356. </div>
  357. </div>
  358. </div>
  359. <?php
  360. }
  361. /**
  362. * Renders the full-screen connection prompt. Only shown once and on plugin activation.
  363. */
  364. public static function render_connect_prompt_full_screen() {
  365. $current_screen = get_current_screen();
  366. if ( 'plugins' === $current_screen->base ) {
  367. $bottom_connect_url_from = 'full-screen-prompt';
  368. } else {
  369. $bottom_connect_url_from = 'landing-page-bottom';
  370. }
  371. $has_no_owner = ! Jetpack::connection()->has_connected_owner();
  372. ?>
  373. <div class="jp-connect-full__container <?php echo $has_no_owner ? 'jp-jetpack-connect__site_connection' : ''; ?>"><div class="jp-connect-full__container-card">
  374. <?php if ( 'plugins' === $current_screen->base ) : ?>
  375. <?php
  376. $logo = new Logo();
  377. echo $logo->render();
  378. ?>
  379. <?php
  380. if ( ! self::force_display() ) :
  381. ?>
  382. <div class="jp-connect-full__dismiss">
  383. <svg class="jp-connect-full__svg-dismiss" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><title>Dismiss Jetpack Connection Window</title><rect x="0" fill="none" /><g><path d="M17.705 7.705l-1.41-1.41L12 10.59 7.705 6.295l-1.41 1.41L10.59 12l-4.295 4.295 1.41 1.41L12 13.41l4.295 4.295 1.41-1.41L13.41 12l4.295-4.295z"/></g></svg>
  384. </div>
  385. <?php
  386. endif;
  387. ?>
  388. <?php endif; ?>
  389. <div id="jp-connect-full__step1-header" class="jp-connect-full__step-header">
  390. <h2 class="jp-connect-full__step-header-title"><?php esc_html_e( 'Activate essential WordPress security and performance tools by setting up Jetpack', 'jetpack' ); ?></h2>
  391. </div>
  392. <div id="jp-connect-full__step2-header" class="jp-connect-full__step-header">
  393. <h2 class="jp-connect-full__step-header-title"><?php esc_html_e( 'Jetpack is activated!', 'jetpack' ); ?><br /><?php esc_html_e( 'Unlock more amazing features by connecting a user account', 'jetpack' ); ?></h2>
  394. </div>
  395. <p class="jp-connect-full__tos-blurb">
  396. <?php jetpack_render_tos_blurb(); ?>
  397. </p>
  398. <p class="jp-connect-full__button-container">
  399. <a href="<?php echo esc_url( Jetpack::init()->build_connect_url( true, false, $bottom_connect_url_from ) ); ?>"
  400. class="dops-button is-primary jp-connect-button">
  401. <?php esc_html_e( 'Set up Jetpack', 'jetpack' ); ?>
  402. </a>
  403. </p>
  404. <div class="jp-connect-full__row" id="jetpack-connection-cards">
  405. <div class="jp-connect-full__slide">
  406. <div class="jp-connect-full__slide-card illustration">
  407. <img
  408. src="<?php echo plugins_url( 'images/jetpack-connection-security.svg', JETPACK__PLUGIN_FILE ); ?>"
  409. alt="<?php esc_attr_e( 'Security & Backups', 'jetpack' ); ?>"
  410. />
  411. </div>
  412. <div class="jp-connect-full__slide-card">
  413. <h3><?php esc_html_e( 'Always-on Security', 'jetpack' ); ?></h3>
  414. <ul>
  415. <li><?php esc_html_e( 'Stay one step ahead of security threats with automatic scanning, one-click fixes, and spam protection.', 'jetpack' ); ?></li>
  416. <li><?php esc_html_e( 'Real-time backups save every change and one-click restores get you back online quickly.', 'jetpack' ); ?></li>
  417. <li><?php esc_html_e( 'Free protection against brute force attacks and instant notifications if your site goes down.', 'jetpack' ); ?></li>
  418. </ul>
  419. </div>
  420. </div>
  421. <div class="jp-connect-full__slide">
  422. <div class="jp-connect-full__slide-card illustration">
  423. <img
  424. src="<?php echo plugins_url( 'images/jetpack-connection-performance.svg', JETPACK__PLUGIN_FILE ); ?>"
  425. alt="<?php esc_attr_e( 'Built-in Performance', 'jetpack' ); ?>"
  426. />
  427. </div>
  428. <div class="jp-connect-full__slide-card">
  429. <h3><?php esc_html_e( 'Built-in Performance', 'jetpack' ); ?></h3>
  430. <ul>
  431. <li><?php esc_html_e( 'Keep people on your site longer with lightning-fast page load times through our free global CDN.', 'jetpack' ); ?></li>
  432. <li><?php esc_html_e( 'Speed up your mobile site and reduce bandwidth usage automatically.', 'jetpack' ); ?></li>
  433. <li><?php esc_html_e( 'Improve visitor engagement and sales with a customized search experience.', 'jetpack' ); ?></li>
  434. </ul>
  435. </div>
  436. </div>
  437. </div>
  438. <h2 class="jp-connect-full__testimonial"><?php esc_html_e( 'More than 5 million WordPress sites trust Jetpack for their website security and performance.', 'jetpack' ); ?></h2>
  439. <?php if ( 'plugins' === $current_screen->base ) : ?>
  440. <?php
  441. if ( ! self::force_display() ) :
  442. ?>
  443. <p class="jp-connect-full__dismiss-paragraph">
  444. <a>
  445. <?php
  446. echo esc_html_x(
  447. 'Not now, thank you.',
  448. 'a link that closes the modal window that offers to connect Jetpack',
  449. 'jetpack'
  450. );
  451. ?>
  452. </a>
  453. </p>
  454. <?php
  455. endif;
  456. ?>
  457. <?php endif; ?>
  458. </div>
  459. </div>
  460. <?php
  461. }
  462. /**
  463. * Renders the legacy network connection banner.
  464. */
  465. function network_connect_notice() {
  466. ?>
  467. <div id="message" class="updated jetpack-message">
  468. <div class="squeezer">
  469. <h2>
  470. <?php
  471. echo wp_kses(
  472. __(
  473. '<strong>Jetpack is activated!</strong> Each site on your network must be connected individually by an admin on that site.',
  474. 'jetpack'
  475. ),
  476. array( 'strong' => array() )
  477. );
  478. ?>
  479. </h2>
  480. </div>
  481. </div>
  482. <?php
  483. }
  484. }