updated plugin Jetpack Protect version 1.0.4

This commit is contained in:
2022-09-02 15:19:40 +00:00
committed by Gitium
parent ba0955a33f
commit 1ecbe8cf47
99 changed files with 8263 additions and 935 deletions

View File

@ -0,0 +1,574 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [2.2.26] - 2022-08-29
### Changed
- Updated package dependencies.
## [2.2.25] - 2022-08-25
### Changed
- Updated package dependencies. [#25814]
## [2.2.24] - 2022-08-23
### Added
- Add custom styling rules for the JITMs displayed in My Jetpack. [#22452]
- Updated JITM readme. [#25739]
### Changed
- Updated package dependencies. [#25628]
## [2.2.23] - 2022-08-03
### Changed
- Updated package dependencies. [#25300, #25315]
## [2.2.22] - 2022-07-26
### Changed
- Updated package dependencies. [#25158]
## [2.2.21] - 2022-07-12
### Changed
- Updated package dependencies.
## [2.2.20] - 2022-06-21
### Changed
- Renaming master to trunk. [#24661]
## [2.2.19] - 2022-06-14
### Changed
- Updated package dependencies. [#24529]
## [2.2.18] - 2022-06-08
### Changed
- Reorder JS imports for `import/order` eslint rule. [#24601]
## [2.2.17] - 2022-05-18
### Changed
- Updated package dependencies [#24372]
## [2.2.16] - 2022-05-10
### Changed
- Updated package dependencies. [#24302]
## [2.2.15] - 2022-05-04
### Changed
- Remove use of `pnpx` in preparation for pnpm 7.0. [#24210]
- Updated package dependencies. [#24095]
### Deprecated
- Moved the options class into Connection. [#24095]
## [2.2.14] - 2022-04-26
### Changed
- Updated package dependencies.
- Update package.json metadata.
## [2.2.13] - 2022-04-19
### Changed
- PHPCS: Fix `WordPress.Security.ValidatedSanitizedInput`
## [2.2.12] - 2022-04-12
### Changed
- Updated package dependencies.
## [2.2.11] - 2022-04-06
### Changed
- Updated package dependencies
### Removed
- Removed tracking dependency.
## [2.2.10] - 2022-03-29
### Changed
- Updated package dependencies.
## [2.2.9] - 2022-03-23
### Changed
- Updated package dependencies.
## [2.2.8] - 2022-03-02
### Changed
- Updated package dependencies
## [2.2.7] - 2022-02-22
### Changed
- Updated package dependencies.
## [2.2.6] - 2022-02-16
### Changed
- Updated package dependencies.
## [2.2.5] - 2022-02-09
### Changed
- Updated package dependencies.
## [2.2.4] - 2022-02-02
### Changed
- Build: remove unneeded files from production build.
- Update use of old jQuery interfaces
## [2.2.3] - 2022-01-25
### Changed
- Updated package dependencies.
## [2.2.2] - 2022-01-18
### Changed
- General: update required node version to v16.13.2
## [2.2.1] - 2022-01-11
### Changed
- Updated package dependencies.
## [2.2.0] - 2022-01-04
### Changed
- Switch to pcov for code coverage.
- Updated package dependencies.
- Updated package textdomain from `jetpack` to `jetpack-jitm`.
## [2.1.1] - 2021-12-14
### Changed
- Updated package dependencies.
## [2.1.0] - 2021-11-30
### Added
- Add proper JS and CSS builder.
- Adds filters to allow sideloading of the Jetpack Backup plugin through JITMs.
- JITM: Added ability to sideload Jetpack Boost plugin.
### Changed
- Add `output.filename` in Webpack config to override changed default.
- Colors: update Jetpack Primary color to match latest brand book.
### Fixed
- JITM: wrap CTA below text on small viewports
## [2.0.8] - 2021-11-23
### Changed
- Updated package dependencies.
## [2.0.7] - 2021-11-16
### Added
- Use monorepo `validate-es` script to validate Webpack builds.
### Changed
- Updated package dependencies.
## [2.0.6] - 2021-11-09
### Changed
- Update webpack build config.
## [2.0.5] - 2021-11-02
### Changed
- Set `convertDeprecationsToExceptions` true in PHPUnit config.
- Update PHPUnit configs to include just what needs coverage rather than include everything then try to exclude stuff that doesn't.
## [2.0.4] - 2021-10-26
### Changed
- Updated package dependencies.
## [2.0.3] - 2021-10-19
### Changed
- Updated package dependencies.
## [2.0.2] - 2021-10-12
### Changed
- Updated package dependencies
## [2.0.1] - 2021-09-28
### Changed
- Allow Node ^14.17.6 to be used in this project. This shouldn't change the behavior of the code itself.
- Updated package dependencies.
## [2.0.0] - 2021-08-31
### Changed
- Run composer update on test-php command instead of phpunit.
- Tests: update PHPUnit polyfills dependency (yoast/phpunit-polyfills).
- Update annotations versions.
- Updated package dependencies.
- Update to latest webpack, webpack-cli and calypso-build.
- Upgrade to Webpack 5.
- Use Node 16.7.0 in tooling.
### Removed
- Removed IE11 support.
## [1.16.2] - 2021-07-27
### Changed
- Updated package dependencies.
## [1.16.1] - 2021-06-29
### Changed
- Update package dependencies.
- Update node version requirement to 14.16.1
- Update the usage of Redirect lib and passes the unlinked param as a query argument.
## [1.16.0] - 2021-05-25
### Added
- JITM: allow the plugin to set the icon for pre-connection JITMs.
- JITM: move sync updated option hook to the JITM package.
### Changed
- JITM: prevent JITMs from being registered more than once.
- JITM: remove jetpack-constants dependency from composer.json
- JITM: set the default values of the jetpack_just_in_time_msgs and jetpack_just_in_time_msg_cache filters to true.
- JITM: Use an action instead of a property to prevent JITMs from being registered multiple times
- JITM: Use the Device_Detection package to determine if the device is mobile.
- Updated package dependencies
- update jetpack-redirect dependency
## [1.15.1] - 2021-05-03
### Changed
- JITM: Use manager::get_authorization_url to obtain the authorization url in the user deletion notice.
## [1.15.0] - 2021-04-27
### Added
- Move JITM's REST API endpoints into the package
### Changed
- Always display pre-connection JITMs, without the need to set a filter.
- Avoid wrapping text in the main CTA button.
- Bump JITM package version requirement.
- JITM: Update CTA redirect url with unlinked query arg to indicate current user is not connected.
- Update package dependencies.
- Use the a8c-mc-stats package to generate stats.
## [1.14.1] - 2021-03-30
### Added
- Composer alias for dev-master, to improve dependencies
### Changed
- Use is_connected instead of is_active to instantiate Pre/Post_Connection_JITM
- Add a jetpack_pre_connection_jitms filter.
- Update colors to match upcoming WP 5.7 color changes
- Update Node to match latest LTS 12
- Update package dependencies.
### Fixed
- Use `composer update` rather than `install` in scripts, as composer.lock isn't checked in.
## [1.14.0] - 2021-02-23
- Recommendations: Hide JITMs when banner is displaying
- Setup Wizard: Remove setup wizard
- JITM: move jetpack-jitm.js to the JITM package
- CI: Make tests more generic
## [1.13.5] - 2021-02-08
- Update dependencies to latest stable
## [1.13.4] - 2021-01-28
- Update dependencies to latest stable
## [1.13.3] - 2021-01-26
- Update dependencies to latest stable
## [1.13.2] - 2021-01-26
- Update dependencies to latest stable
## [1.13.1] - 2021-01-26
- Add mirror-repo information to all current composer packages
- Monorepo: Reorganize all projects
## [1.13.0] - 2021-01-05
- Update dependency brain/monkey to v2.6.0
- Pin dependencies
- Packages: Update for PHP 8 testing
## [1.12.2] - 2020-12-09
- Update dependencies to latest stable
## [1.12.1] - 2020-11-24
- Version packages for release
## [1.12.0] - 2020-11-24
- Status: Introduce get_site_suffix method
- General: update minimum required version to WordPress 5.5
- Updated PHPCS: Packages and Debugger
## [1.11.2] - 2020-11-05
- Update dependencies to latest stable
## [1.11.1] - 2020-10-29
- Update dependencies to latest stable
## [1.11.0] - 2020-10-27
- JITM: add a Pre_Connection_JITM::generate_admin_url method
- JITM: use is_active from the connection package
- JITM: regenerate assets
## [1.10.4] - 2020-10-14
- Update dependencies to latest stable
## [1.10.3] - 2020-10-09
- Update dependencies to latest stable
## [1.10.2] - 2020-10-06
- Update dependencies to latest stable
## [1.10.1] - 2020-10-01
- Update dependencies to latest stable
## [1.10.0] - 2020-09-29
- Update dependencies to latest stable
## [1.9.1] - 2020-09-09
- Update dependencies to latest stable
## [1.9.0] - 2020-08-26
- Compat: add new Creative Mail compat file
- Packages: Update filenames after #16810
- CI: Try collect js coverage
- Docker: Add package testing shortcut
## [1.8.2] - 2020-08-10
- Update dependencies to latest stable
## [1.8.1] - 2020-08-10
- Update dependencies to latest stable
## [1.8.0] - 2020-07-28
- Core Compat: Site Environment
- Core REST API: Add permission callback to delete_jitm_message endpoint
## [1.7.2] - 2020-07-06
- Update dependencies to latest stable
## [1.7.1] - 2020-07-01
- Update dependencies to latest stable
## [1.7.0] - 2020-06-30
- PHPCS: Clean up the packages
- Hide pre-connection JITM on the posts page when few posts are published
- Jetpack Setup Wizard: Do not show pre-connection JITMs to non admins
- JITM: change 'setup' to 'set up' in pre-connection JITMs
- Pre-connection JITMS: Link to connect-in-place flow
- JITM: add Redirect use statement
## [1.6.5] - 2020-06-01
- Hide pre-connection JITM on the posts page when few posts are published
## [1.6.4] - 2020-06-01
- Update dependencies to latest stable
## [1.6.3] - 2020-05-29
- Jetpack Setup Wizard: Do not show pre-connection JITMs to non admins
## [1.6.2] - 2020-05-29
- JITM: change 'setup' to 'set up' in pre-connection JITMs
- Pre-connection JITMS: Link to connect-in-place flow
## [1.6.1] - 2020-05-28
- JITM: add Redirect use statement
## [1.6.0] - 2020-05-26
- JITM: expand docs and tests to account for pre-connection messages
- Improve responsiveness of JITMs
- JITM: fix the use statements
- Implement pre-connection JITMs
- JITM: Allow JITM on stats pages
## [1.5.1] - 2020-04-30
- JITM: Allow JITM on stats pages
## [1.5.0] - 2020-04-28
- Use jp.com redirect in all links
## [1.4.0] - 2020-03-31
- Update dependencies to latest stable
## [1.3.0] - 2020-03-31
- Use dynamic Jetpack logos on JITMs
## [1.2.0] - 2020-02-25
- JITM: Show ToS update notice
## [1.1.2] - 2020-02-14
- SSO: do not display JITM when not in wp-admin
## [1.1.1] - 2020-01-23
- Moved JITM initialization to plugins_loaded.
## [1.1.0] - 2020-01-07
- Add partner subsidiary id to upgrade URLs.
## [1.0.10] - 2019-11-25
- Connection Owner Deletion Notice: Fix display bug and sanitize…
## [1.0.9] - 2019-11-19
- Don't show JITMs on Gutenberg editor pages (for now)
## [1.0.8] - 2019-11-08
- Packages: Use classmap instead of PSR-4
## [1.0.7] - 2019-11-08
- Remove unused get_emblem method
## [1.0.6] - 2019-10-31
- Inherit 400 weight for button fonts
## [1.0.5] - 2019-10-28
- PHPCS: JITM and Assets packages
## [1.0.4] - 2019-10-24
- Update Jetpack button and card styles to match WordPress 5.3
## [1.0.3] - 2019-10-23
- Use spread operator instead of func_get_args
## [1.0.2] - 2019-10-17
- Change the class in the add_filter() calls to $this. Also fix some
## [1.0.1] - 2019-09-27
- Initial trial of prefer-dist
- JITM: Send the user's role in the request for JITM messages
## 1.0.0 - 2019-09-14
- Update Jetpack to use new JITM package
[2.2.26]: https://github.com/Automattic/jetpack-jitm/compare/v2.2.25...v2.2.26
[2.2.25]: https://github.com/Automattic/jetpack-jitm/compare/v2.2.24...v2.2.25
[2.2.24]: https://github.com/Automattic/jetpack-jitm/compare/v2.2.23...v2.2.24
[2.2.23]: https://github.com/Automattic/jetpack-jitm/compare/v2.2.22...v2.2.23
[2.2.22]: https://github.com/Automattic/jetpack-jitm/compare/v2.2.21...v2.2.22
[2.2.21]: https://github.com/Automattic/jetpack-jitm/compare/v2.2.20...v2.2.21
[2.2.20]: https://github.com/Automattic/jetpack-jitm/compare/v2.2.19...v2.2.20
[2.2.19]: https://github.com/Automattic/jetpack-jitm/compare/v2.2.18...v2.2.19
[2.2.18]: https://github.com/Automattic/jetpack-jitm/compare/v2.2.17...v2.2.18
[2.2.17]: https://github.com/Automattic/jetpack-jitm/compare/v2.2.16...v2.2.17
[2.2.16]: https://github.com/Automattic/jetpack-jitm/compare/v2.2.15...v2.2.16
[2.2.15]: https://github.com/Automattic/jetpack-jitm/compare/v2.2.14...v2.2.15
[2.2.14]: https://github.com/Automattic/jetpack-jitm/compare/v2.2.13...v2.2.14
[2.2.13]: https://github.com/Automattic/jetpack-jitm/compare/v2.2.12...v2.2.13
[2.2.12]: https://github.com/Automattic/jetpack-jitm/compare/v2.2.11...v2.2.12
[2.2.11]: https://github.com/Automattic/jetpack-jitm/compare/v2.2.10...v2.2.11
[2.2.10]: https://github.com/Automattic/jetpack-jitm/compare/v2.2.9...v2.2.10
[2.2.9]: https://github.com/Automattic/jetpack-jitm/compare/v2.2.8...v2.2.9
[2.2.8]: https://github.com/Automattic/jetpack-jitm/compare/v2.2.7...v2.2.8
[2.2.7]: https://github.com/Automattic/jetpack-jitm/compare/v2.2.6...v2.2.7
[2.2.6]: https://github.com/Automattic/jetpack-jitm/compare/v2.2.5...v2.2.6
[2.2.5]: https://github.com/Automattic/jetpack-jitm/compare/v2.2.4...v2.2.5
[2.2.4]: https://github.com/Automattic/jetpack-jitm/compare/v2.2.3...v2.2.4
[2.2.3]: https://github.com/Automattic/jetpack-jitm/compare/v2.2.2...v2.2.3
[2.2.2]: https://github.com/Automattic/jetpack-jitm/compare/v2.2.1...v2.2.2
[2.2.1]: https://github.com/Automattic/jetpack-jitm/compare/v2.2.0...v2.2.1
[2.2.0]: https://github.com/Automattic/jetpack-jitm/compare/v2.1.1...v2.2.0
[2.1.1]: https://github.com/Automattic/jetpack-jitm/compare/v2.1.0...v2.1.1
[2.1.0]: https://github.com/Automattic/jetpack-jitm/compare/v2.0.8...v2.1.0
[2.0.8]: https://github.com/Automattic/jetpack-jitm/compare/v2.0.7...v2.0.8
[2.0.7]: https://github.com/Automattic/jetpack-jitm/compare/v2.0.6...v2.0.7
[2.0.6]: https://github.com/Automattic/jetpack-jitm/compare/v2.0.5...v2.0.6
[2.0.5]: https://github.com/Automattic/jetpack-jitm/compare/v2.0.4...v2.0.5
[2.0.4]: https://github.com/Automattic/jetpack-jitm/compare/v2.0.3...v2.0.4
[2.0.3]: https://github.com/Automattic/jetpack-jitm/compare/v2.0.2...v2.0.3
[2.0.2]: https://github.com/Automattic/jetpack-jitm/compare/v2.0.1...v2.0.2
[2.0.1]: https://github.com/Automattic/jetpack-jitm/compare/v2.0.0...v2.0.1
[2.0.0]: https://github.com/Automattic/jetpack-jitm/compare/v1.16.2...v2.0.0
[1.16.2]: https://github.com/Automattic/jetpack-jitm/compare/v1.16.1...v1.16.2
[1.16.1]: https://github.com/Automattic/jetpack-jitm/compare/v1.16.0...v1.16.1
[1.16.0]: https://github.com/Automattic/jetpack-jitm/compare/v1.15.1...v1.16.0
[1.15.1]: https://github.com/Automattic/jetpack-jitm/compare/v1.15.0...v1.15.1
[1.15.0]: https://github.com/Automattic/jetpack-jitm/compare/v1.14.1...v1.15.0
[1.14.1]: https://github.com/Automattic/jetpack-jitm/compare/v1.14.0...v1.14.1
[1.14.0]: https://github.com/Automattic/jetpack-jitm/compare/v1.13.5...v1.14.0
[1.13.5]: https://github.com/Automattic/jetpack-jitm/compare/v1.13.4...v1.13.5
[1.13.4]: https://github.com/Automattic/jetpack-jitm/compare/v1.13.3...v1.13.4
[1.13.3]: https://github.com/Automattic/jetpack-jitm/compare/v1.13.2...v1.13.3
[1.13.2]: https://github.com/Automattic/jetpack-jitm/compare/v1.13.1...v1.13.2
[1.13.1]: https://github.com/Automattic/jetpack-jitm/compare/v1.13.0...v1.13.1
[1.13.0]: https://github.com/Automattic/jetpack-jitm/compare/v1.12.2...v1.13.0
[1.12.2]: https://github.com/Automattic/jetpack-jitm/compare/v1.12.1...v1.12.2
[1.12.1]: https://github.com/Automattic/jetpack-jitm/compare/v1.12.0...v1.12.1
[1.12.0]: https://github.com/Automattic/jetpack-jitm/compare/v1.11.2...v1.12.0
[1.11.2]: https://github.com/Automattic/jetpack-jitm/compare/v1.11.1...v1.11.2
[1.11.1]: https://github.com/Automattic/jetpack-jitm/compare/v1.11.0...v1.11.1
[1.11.0]: https://github.com/Automattic/jetpack-jitm/compare/v1.10.4...v1.11.0
[1.10.4]: https://github.com/Automattic/jetpack-jitm/compare/v1.10.3...v1.10.4
[1.10.3]: https://github.com/Automattic/jetpack-jitm/compare/v1.10.2...v1.10.3
[1.10.2]: https://github.com/Automattic/jetpack-jitm/compare/v1.10.1...v1.10.2
[1.10.1]: https://github.com/Automattic/jetpack-jitm/compare/v1.10.0...v1.10.1
[1.10.0]: https://github.com/Automattic/jetpack-jitm/compare/v1.9.1...v1.10.0
[1.9.1]: https://github.com/Automattic/jetpack-jitm/compare/v1.9.0...v1.9.1
[1.9.0]: https://github.com/Automattic/jetpack-jitm/compare/v1.8.2...v1.9.0
[1.8.2]: https://github.com/Automattic/jetpack-jitm/compare/v1.8.1...v1.8.2
[1.8.1]: https://github.com/Automattic/jetpack-jitm/compare/v1.8.0...v1.8.1
[1.8.0]: https://github.com/Automattic/jetpack-jitm/compare/v1.7.2...v1.8.0
[1.7.2]: https://github.com/Automattic/jetpack-jitm/compare/v1.7.1...v1.7.2
[1.7.1]: https://github.com/Automattic/jetpack-jitm/compare/v1.7.0...v1.7.1
[1.7.0]: https://github.com/Automattic/jetpack-jitm/compare/v1.6.5...v1.7.0
[1.6.5]: https://github.com/Automattic/jetpack-jitm/compare/v1.6.4...v1.6.5
[1.6.4]: https://github.com/Automattic/jetpack-jitm/compare/v1.6.3...v1.6.4
[1.6.3]: https://github.com/Automattic/jetpack-jitm/compare/v1.6.2...v1.6.3
[1.6.2]: https://github.com/Automattic/jetpack-jitm/compare/v1.6.1...v1.6.2
[1.6.1]: https://github.com/Automattic/jetpack-jitm/compare/v1.6.0...v1.6.1
[1.6.0]: https://github.com/Automattic/jetpack-jitm/compare/v1.5.1...v1.6.0
[1.5.1]: https://github.com/Automattic/jetpack-jitm/compare/v1.5.0...v1.5.1
[1.5.0]: https://github.com/Automattic/jetpack-jitm/compare/v1.4.0...v1.5.0
[1.4.0]: https://github.com/Automattic/jetpack-jitm/compare/v1.3.0...v1.4.0
[1.3.0]: https://github.com/Automattic/jetpack-jitm/compare/v1.2.0...v1.3.0
[1.2.0]: https://github.com/Automattic/jetpack-jitm/compare/v1.1.2...v1.2.0
[1.1.2]: https://github.com/Automattic/jetpack-jitm/compare/v1.1.1...v1.1.2
[1.1.1]: https://github.com/Automattic/jetpack-jitm/compare/v1.1.0...v1.1.1
[1.1.0]: https://github.com/Automattic/jetpack-jitm/compare/v1.0.10...v1.1.0
[1.0.10]: https://github.com/Automattic/jetpack-jitm/compare/v1.0.9...v1.0.10
[1.0.9]: https://github.com/Automattic/jetpack-jitm/compare/v1.0.8...v1.0.9
[1.0.8]: https://github.com/Automattic/jetpack-jitm/compare/v1.0.7...v1.0.8
[1.0.7]: https://github.com/Automattic/jetpack-jitm/compare/v1.0.6...v1.0.7
[1.0.6]: https://github.com/Automattic/jetpack-jitm/compare/v1.0.5...v1.0.6
[1.0.5]: https://github.com/Automattic/jetpack-jitm/compare/v1.0.4...v1.0.5
[1.0.4]: https://github.com/Automattic/jetpack-jitm/compare/v1.0.3...v1.0.4
[1.0.3]: https://github.com/Automattic/jetpack-jitm/compare/v1.0.2...v1.0.3
[1.0.2]: https://github.com/Automattic/jetpack-jitm/compare/v1.0.1...v1.0.2
[1.0.1]: https://github.com/Automattic/jetpack-jitm/compare/v1.0.0...v1.0.1

View File

@ -0,0 +1,357 @@
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===================================
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View File

@ -0,0 +1,38 @@
# Security Policy
Full details of the Automattic Security Policy can be found on [automattic.com](https://automattic.com/security/).
## Supported Versions
Generally, only the latest version of Jetpack has continued support. If a critical vulnerability is found in the current version of Jetpack, we may opt to backport any patches to previous versions.
## Reporting a Vulnerability
[Jetpack](https://jetpack.com/) is an open-source plugin for WordPress. Our HackerOne program covers the plugin software, as well as a variety of related projects and infrastructure.
**For responsible disclosure of security issues and to be eligible for our bug bounty program, please submit your report via the [HackerOne](https://hackerone.com/automattic) portal.**
Our most critical targets are:
* Jetpack and the Jetpack composer packages (all within this repo)
* Jetpack.com -- the primary marketing site.
* cloud.jetpack.com -- a management site.
* wordpress.com -- the shared management site for both Jetpack and WordPress.com sites.
For more targets, see the `In Scope` section on [HackerOne](https://hackerone.com/automattic).
_Please note that the **WordPress software is a separate entity** from Automattic. Please report vulnerabilities for WordPress through [the WordPress Foundation's HackerOne page](https://hackerone.com/wordpress)._
## Guidelines
We're committed to working with security researchers to resolve the vulnerabilities they discover. You can help us by following these guidelines:
* Follow [HackerOne's disclosure guidelines](https://www.hackerone.com/disclosure-guidelines).
* Pen-testing Production:
* Please **setup a local environment** instead whenever possible. Most of our code is open source (see above).
* If that's not possible, **limit any data access/modification** to the bare minimum necessary to reproduce a PoC.
* **_Don't_ automate form submissions!** That's very annoying for us, because it adds extra work for the volunteers who manage those systems, and reduces the signal/noise ratio in our communication channels.
* To be eligible for a bounty, all of these guidelines must be followed.
* Be Patient - Give us a reasonable time to correct the issue before you disclose the vulnerability.
We also expect you to comply with all applicable laws. You're responsible to pay any taxes associated with your bounties.

View File

@ -0,0 +1 @@
<?php return array('dependencies' => array('wp-polyfill'), 'version' => '2844220d1ce117cbcaed');

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
(()=>{"use strict";jQuery(document).ready((function(t){var a={default:function(a){var e='<div class="jitm-card jitm-banner '+(a.CTA.message?"has-call-to-action":"")+" is-upgrade-premium "+a.content.classes+'" data-stats_url="'+a.jitm_stats_url+'">';if(e+='<div class="jitm-banner__content">',e+='<div class="jitm-banner__icon-plan">'+a.content.icon+"</div>",e+='<div class="jitm-banner__info">',e+='<div class="jitm-banner__title">'+a.content.message+"</div>",a.content.description&&""!==a.content.description){if(e+='<div class="jitm-banner__description">'+a.content.description,a.content.list.length>0){e+='<ul class="banner__list">';for(var i=0;i<a.content.list.length;i++){var n=a.content.list[i].item;a.content.list[i].url&&(n='<a href="'+a.content.list[i].url+'" target="_blank" rel="noopener noreferrer" data-module="'+a.feature_class+'" data-jptracks-name="nudge_item_click" data-jptracks-prop="jitm-'+a.id+'">'+n+"</a>"),e+='<li><svg class="gridicon gridicons-checkmark" height="16" width="16" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g><path d="M9 19.414l-6.707-6.707 1.414-1.414L9 16.586 20.293 5.293l1.414 1.414" /></g></svg>'+n+"</li>"}}e+="</div>"}if(e+="</div>",e+="</div>",e+='<div class="jitm-banner__buttons_container">',a.activate_module&&(e+='<div class="jitm-banner__action" id="jitm-banner__activate">',e+='<a href="#" data-module="'+a.activate_module+'" type="button" class="jitm-button is-compact is-primary jptracks" data-jptracks-name="nudge_click" data-jptracks-prop="jitm-'+a.id+'-activate_module">'+window.jitm_config.activate_module_text+"</a>",e+="</div>"),a.CTA.message){var c="jitm-button is-compact jptracks";a.CTA.primary&&null===a.activate_module&&(c+=" is-primary");var o=a.CTA.ajax_action;e+='<div class="jitm-banner__action">',e+='<a href="'+(a.CTA.hasOwnProperty("link")&&a.CTA.link.length?a.CTA.link:a.url)+'" target="'+(!1===a.CTA.newWindow||o?"_self":"_blank")+'" rel="noopener noreferrer" title="'+a.CTA.message+'" data-module="'+a.feature_class+'" type="button" class="'+c+'" data-jptracks-name="nudge_click" data-jptracks-prop="jitm-'+a.id+'" '+(o?'data-ajax-action="'+o+'"':"")+">"+a.CTA.message+"</a>",e+="</div>"}return e+="</div>",a.is_dismissible&&(e+='<a href="#" data-module="'+a.feature_class+'" class="jitm-banner__dismiss"></a>'),t(e+="</div>")}},e=function(){t(".jetpack-jitm-message").each((function(){var e=t(this),i=e.data("message-path"),n=e.data("query"),c=e.data("redirect"),o=location.hash;"_dashboard"!==(o=o.replace(/#\//,"_"))&&(i=i.replace("toplevel_page_jetpack","toplevel_page_jetpack"+o));var r=!!t(".jetpack-logo__masthead").length;t.get(window.jitm_config.api_root+"jetpack/v4/jitm",{message_path:i,query:n,full_jp_logo_exists:r,_wpnonce:e.data("nonce")}).then((function(i){"object"==typeof i&&i[1]&&(i=[i[1]]),0!==i.length&&i[0].content&&function(e,i,n){var c;(c=i.template)&&a[c]||(c="default"),i.url=i.url+"&redirect="+n;var o,r=a[c](i);r.find(".jitm-banner__dismiss").on("click",(o=r,function(a){a.preventDefault(),o.hide(),t.ajax({url:window.jitm_config.api_root+"jetpack/v4/jitm",method:"POST",beforeSend:function(t){t.setRequestHeader("X-WP-Nonce",window.jitm_config.nonce)},data:{id:i.id,feature_class:i.feature_class}})})),t("#jp-admin-notices").length>0?(e.innerHTML=r,t("#jp-admin-notices").find(".jitm-card")&&t(".jitm-card").replaceWith(r),r.prependTo(t("#jp-admin-notices"))):e.replaceWith(r),r.find("#jitm-banner__activate a").on("click",(function(){var a=t(this);if(a.attr("disabled"))return!1;t.ajax({url:window.jitm_config.api_root+"jetpack/v4/module/"+a.data("module")+"/active",method:"POST",beforeSend:function(a){a.setRequestHeader("X-WP-Nonce",e.data("nonce")),t("#jitm-banner__activate a").text(window.jitm_config.activating_module_text),t("#jitm-banner__activate a").attr("disabled",!0)}}).done((function(){t("#jitm-banner__activate a").text(window.jitm_config.activated_module_text),t("#jitm-banner__activate a").attr("disabled",!0),setTimeout((function(){r.fadeOut("slow")}),2e3)}))})),r.find(".jitm-button[data-ajax-action]").on("click",(function(a){a.preventDefault();var i=t(this);return i.attr("disabled",!0),t.post(window.ajaxurl,{action:i.data("ajax-action"),_nonce:e.data("ajax-nonce")}).done((function(){r.fadeOut("slow")})).fail((function(){i.attr("disabled",!1)})),!1}))}(e,i[0],c)}))}))};e(),t(window).on("hashchange",(function(t){if(t.originalEvent.newURL.indexOf("jetpack#/")>=0){var a=document.querySelector(".jitm-card");a&&a.remove(),e()}}))}))})();

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,59 @@
{
"name": "automattic/jetpack-jitm",
"description": "Just in time messages for Jetpack",
"type": "jetpack-library",
"license": "GPL-2.0-or-later",
"require": {
"automattic/jetpack-a8c-mc-stats": "^1.4",
"automattic/jetpack-assets": "^1.17",
"automattic/jetpack-connection": "^1.44",
"automattic/jetpack-device-detection": "^1.4",
"automattic/jetpack-logo": "^1.5",
"automattic/jetpack-partner": "^1.7",
"automattic/jetpack-redirect": "^1.7",
"automattic/jetpack-status": "^1.14"
},
"require-dev": {
"brain/monkey": "2.6.1",
"yoast/phpunit-polyfills": "1.0.3",
"automattic/jetpack-changelogger": "^3.2"
},
"autoload": {
"classmap": [
"src/"
]
},
"scripts": {
"build-production": [
"pnpm run build-production"
],
"build-development": [
"pnpm run build"
],
"phpunit": [
"./vendor/phpunit/phpunit/phpunit --colors=always"
],
"test-coverage": [
"php -dpcov.directory=. ./vendor/bin/phpunit --coverage-clover \"$COVERAGE_DIR/clover.xml\""
],
"test-php": [
"@composer phpunit"
]
},
"minimum-stability": "dev",
"prefer-stable": true,
"extra": {
"autotagger": true,
"mirror-repo": "Automattic/jetpack-jitm",
"textdomain": "jetpack-jitm",
"version-constants": {
"::PACKAGE_VERSION": "src/class-jitm.php"
},
"changelogger": {
"link-template": "https://github.com/Automattic/jetpack-jitm/compare/v${old}...v${new}"
},
"branch-alias": {
"dev-trunk": "2.2.x-dev"
}
}
}

View File

@ -0,0 +1,312 @@
<?php
/**
* Jetpack's JITM class.
*
* @package automattic/jetpack-jitm
*/
namespace Automattic\Jetpack\JITMS;
use Automattic\Jetpack\Assets;
use Automattic\Jetpack\Assets\Logo as Jetpack_Logo;
use Automattic\Jetpack\Connection\Manager as Connection_Manager;
use Automattic\Jetpack\Status;
/**
* Jetpack just in time messaging through out the admin
*
* @since 1.1.0
* @since-jetpack 5.6.0
*/
class JITM {
const PACKAGE_VERSION = '2.2.26';
/**
* The configuration method that is called from the jetpack-config package.
*/
public static function configure() {
$jitm = self::get_instance();
$jitm->register();
}
/**
* Pre/Post Connection JITM factory metod
*
* @return Post_Connection_JITM|Pre_Connection_JITM JITM instance.
*/
public static function get_instance() {
if ( ( new Connection_Manager() )->is_connected() ) {
$jitm = new Post_Connection_JITM();
} else {
$jitm = new Pre_Connection_JITM();
}
return $jitm;
}
/**
* Sets up JITM action callbacks if needed.
*/
public function register() {
if ( did_action( 'jetpack_registered_jitms' ) ) {
// JITMs have already been registered.
return;
}
if ( ! $this->jitms_enabled() ) {
// Do nothing.
return;
}
add_action( 'rest_api_init', array( __NAMESPACE__ . '\\Rest_Api_Endpoints', 'register_endpoints' ) );
add_action( 'current_screen', array( $this, 'prepare_jitms' ) );
/**
* These are sync actions that we need to keep track of for jitms.
*/
add_filter( 'jetpack_sync_before_send_updated_option', array( $this, 'jetpack_track_last_sync_callback' ), 99 );
/**
* Fires when the JITMs are registered. This action is used to ensure that
* JITMs are registered only once.
*
* @since 1.16.0
*/
do_action( 'jetpack_registered_jitms' );
}
/**
* Checks the jetpack_just_in_time_msgs filters and whether the site
* is offline to determine whether JITMs are enabled.
*
* @return bool True if JITMs are enabled, else false.
*/
public function jitms_enabled() {
/**
* Filter to turn off all just in time messages
*
* @since 1.1.0
* @since-jetpack 3.7.0
* @since-jetpack 5.4.0 Correct docblock to reflect default arg value
*
* @param bool true Whether to show just in time messages.
*/
if ( ! apply_filters( 'jetpack_just_in_time_msgs', true ) ) {
return false;
}
// Folks cannot connect to WordPress.com and won't really be able to act on the pre-connection messages. So bail.
if ( ( new Status() )->is_offline_mode() ) {
return false;
}
return true;
}
/**
* Prepare actions according to screen and post type.
*
* @since 1.1.0
* @since-jetpack 3.8.2
*
* @uses Jetpack_Autoupdate::get_possible_failures()
*
* @param \WP_Screen $screen WP Core's screen object.
*/
public function prepare_jitms( $screen ) {
/**
* Filter to hide JITMs on certain screens.
*
* @since 1.14.0
*
* @param bool true Whether to show just in time messages.
* @param string $string->id The ID of the current screen.
*/
if ( apply_filters( 'jetpack_display_jitms_on_screen', true, $screen->id ) ) {
add_action( 'admin_enqueue_scripts', array( $this, 'jitm_enqueue_files' ) );
add_action( 'admin_notices', array( $this, 'ajax_message' ) );
add_action( 'edit_form_top', array( $this, 'ajax_message' ) );
}
}
/**
* Function to enqueue jitm css and js
*/
public function jitm_enqueue_files() {
if ( $this->is_gutenberg_page() ) {
return;
}
Assets::register_script(
'jetpack-jitm',
'../build/index.js',
__FILE__,
array(
'in_footer' => true,
'dependencies' => array( 'jquery' ),
)
);
Assets::enqueue_script( 'jetpack-jitm' );
wp_localize_script(
'jetpack-jitm',
'jitm_config',
array(
'api_root' => esc_url_raw( rest_url() ),
'activate_module_text' => esc_html__( 'Activate', 'jetpack-jitm' ),
'activated_module_text' => esc_html__( 'Activated', 'jetpack-jitm' ),
'activating_module_text' => esc_html__( 'Activating', 'jetpack-jitm' ),
'nonce' => wp_create_nonce( 'wp_rest' ),
)
);
}
/**
* Is the current page a block editor page?
*
* @since 1.1.0
* @since-jetpack 8.0.0
*/
public function is_gutenberg_page() {
$current_screen = get_current_screen();
return ( method_exists( $current_screen, 'is_block_editor' ) && $current_screen->is_block_editor() );
}
/**
* Get's the current message path for display of a JITM
*
* @return string The message path
*/
public function get_message_path() {
$screen = get_current_screen();
return 'wp:' . $screen->id . ':' . current_filter();
}
/**
* Injects the dom to show a JITM inside of wp-admin.
*/
public function ajax_message() {
if ( ! is_admin() ) {
return;
}
// do not display on Gutenberg pages.
if ( $this->is_gutenberg_page() ) {
return;
}
$message_path = $this->get_message_path();
$query_string = _http_build_query( $_GET, '', ',' ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$current_screen = isset( $_SERVER['REQUEST_URI'] ) ? wp_unslash( $_SERVER['REQUEST_URI'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- Escaped below
?>
<div class="jetpack-jitm-message"
data-nonce="<?php echo esc_attr( wp_create_nonce( 'wp_rest' ) ); ?>"
data-ajax-nonce="<?php echo esc_attr( wp_create_nonce( 'wp_ajax_action' ) ); ?>"
data-message-path="<?php echo esc_attr( $message_path ); ?>"
data-query="<?php echo urlencode_deep( $query_string ); ?>"
data-redirect="<?php echo urlencode_deep( $current_screen ); ?>"
></div>
<?php
}
/**
* Generate the icon to display on the JITM.
*
* All icons supported in this method should be included in the array returned by
* JITM::get_supported_icons.
*
* @param string $content_icon Icon type name.
* @param bool $full_jp_logo_exists Is there a big JP logo already displayed on this screen.
*/
public function generate_icon( $content_icon, $full_jp_logo_exists ) {
switch ( $content_icon ) {
case 'jetpack':
$jetpack_logo = new Jetpack_Logo();
$content_icon = '<div class="jp-emblem">' . ( ( $full_jp_logo_exists ) ? $jetpack_logo->get_jp_emblem() : $jetpack_logo->get_jp_emblem_larger() ) . '</div>';
break;
case 'woocommerce':
$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">
.st0{clip-path:url(#SVGID_2_);enable-background:new ;}
.st1{clip-path:url(#SVGID_4_);}
.st2{clip-path:url(#SVGID_6_);}
.st3{clip-path:url(#SVGID_8_);fill:#8F567F;}
.st4{clip-path:url(#SVGID_10_);fill:#FFFFFE;}
.st5{clip-path:url(#SVGID_12_);fill:#FFFFFE;}
.st6{clip-path:url(#SVGID_14_);fill:#FFFFFE;}
</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>';
break;
default:
$content_icon = '';
break;
}
return $content_icon;
}
/**
* Returns an array containing the supported icons for JITMs.
*
* The list includes an empty string, which is used when no icon should be displayed.
*
* @return array The list of supported icons.
*/
public function get_supported_icons() {
return array(
'jetpack',
'woocommerce',
'',
);
}
/**
* Stores dismiss data into an option
*
* @param string $key Dismiss key.
*/
public function save_dismiss( $key ) {
$hide_jitm = \Jetpack_Options::get_option( 'hide_jitm' );
if ( ! is_array( $hide_jitm ) ) {
$hide_jitm = array();
}
if ( ! isset( $hide_jitm[ $key ] ) || ! is_array( $hide_jitm[ $key ] ) ) {
$hide_jitm[ $key ] = array(
'last_dismissal' => 0,
'number' => 0,
);
}
$hide_jitm[ $key ] = array(
'last_dismissal' => time(),
'number' => $hide_jitm[ $key ]['number'] + 1,
);
\Jetpack_Options::update_option( 'hide_jitm', $hide_jitm );
}
/**
* Sets the 'jetpack_last_plugin_sync' transient when the active_plugins option is synced.
*
* @param array $params The action parameters.
*
* @return array Returns the action parameters unchanged.
*/
public function jetpack_track_last_sync_callback( $params ) {
/**
* This filter is documented in the Automattic\Jetpack\JITMS\Post_Connection_JITM class.
*/
if ( ! apply_filters( 'jetpack_just_in_time_msg_cache', true ) ) {
return $params;
}
if ( is_array( $params ) && isset( $params[0] ) ) {
$option = $params[0];
if ( 'active_plugins' === $option ) {
// Use the cache if we can, but not terribly important if it gets evicted.
set_transient( 'jetpack_last_plugin_sync', time(), HOUR_IN_SECONDS );
}
}
return $params;
}
}

View File

@ -0,0 +1,607 @@
<?php
/**
* Jetpack's Post-Connection JITM class.
*
* @package automattic/jetpack-jitm
*/
namespace Automattic\Jetpack\JITMS;
use Automattic\Jetpack\A8c_Mc_Stats;
use Automattic\Jetpack\Connection\Client;
use Automattic\Jetpack\Connection\Manager;
use Automattic\Jetpack\Device_Detection;
use Automattic\Jetpack\Partner;
use Automattic\Jetpack\Redirect;
use Automattic\Jetpack\Tracking;
/**
* Jetpack just in time messaging through out the admin
*
* @since 1.1.0
*
* @since-jetpack 5.6.0
*/
class Post_Connection_JITM extends JITM {
/**
* Tracking object.
*
* @var Automattic\Jetpack\Tracking
*
* @access private
*/
public $tracking;
/**
* JITM constructor.
*/
public function __construct() {
$this->tracking = new Tracking();
}
/**
* Prepare actions according to screen and post type.
*
* @since 1.1.0
* @since-jetpack 3.8.2
*
* @uses Jetpack_Autoupdate::get_possible_failures()
*
* @param \WP_Screen $screen WP Core's screen object.
*/
public function prepare_jitms( $screen ) {
parent::prepare_jitms( $screen );
if ( ! in_array(
$screen->id,
array(
'jetpack_page_akismet-key-config',
'admin_page_jetpack_modules',
),
true
) ) {
// Not really a JITM. Don't know where else to put this :) .
add_action( 'admin_notices', array( $this, 'delete_user_update_connection_owner_notice' ) );
}
}
/**
* A special filter for WooCommerce, to set a message based on local state.
*
* @param string $content The current message.
*
* @return array The new message.
*/
public static function jitm_woocommerce_services_msg( $content ) {
if ( ! function_exists( 'wc_get_base_location' ) ) {
return $content;
}
$base_location = wc_get_base_location();
switch ( $base_location['country'] ) {
case 'US':
$content->message = esc_html__( 'New free service: Show USPS shipping rates on your store! Added bonus: print shipping labels without leaving WooCommerce.', 'jetpack-jitm' );
break;
case 'CA':
$content->message = esc_html__( 'New free service: Show Canada Post shipping rates on your store!', 'jetpack-jitm' );
break;
default:
$content->message = '';
}
return $content;
}
/**
* A special filter for WooCommerce Call To Action button
*
* @return string The new CTA
*/
public static function jitm_jetpack_woo_services_install() {
return wp_nonce_url(
add_query_arg(
array(
'wc-services-action' => 'install',
),
admin_url( 'admin.php?page=wc-settings' )
),
'wc-services-install'
);
}
/**
* A special filter for WooCommerce Call To Action button.
*
* @return string The new CTA
*/
public static function jitm_jetpack_woo_services_activate() {
return wp_nonce_url(
add_query_arg(
array(
'wc-services-action' => 'activate',
),
admin_url( 'admin.php?page=wc-settings' )
),
'wc-services-install'
);
}
/**
* A special filter used in the CTA of a JITM offering to install the Creative Mail plugin.
*
* @return string The new CTA
*/
public static function jitm_jetpack_creative_mail_install() {
return wp_nonce_url(
add_query_arg(
array(
'creative-mail-action' => 'install',
),
admin_url( 'edit.php?post_type=feedback' )
),
'creative-mail-install'
);
}
/**
* A special filter used in the CTA of a JITM offering to activate the Creative Mail plugin.
*
* @return string The new CTA
*/
public static function jitm_jetpack_creative_mail_activate() {
return wp_nonce_url(
add_query_arg(
array(
'creative-mail-action' => 'activate',
),
admin_url( 'edit.php?post_type=feedback' )
),
'creative-mail-install'
);
}
/**
* A special filter used in the CTA of a JITM offering to install the Jetpack Backup plugin.
*
* @return string The new CTA
*/
public static function jitm_jetpack_backup_install() {
return wp_nonce_url(
add_query_arg(
array(
'jetpack-backup-action' => 'install',
),
admin_url( 'admin.php?page=jetpack' )
),
'jetpack-backup-install'
);
}
/**
* A special filter used in the CTA of a JITM offering to activate the Jetpack Backup plugin.
*
* @return string The new CTA
*/
public static function jitm_jetpack_backup_activate() {
return wp_nonce_url(
add_query_arg(
array(
'jetpack-backup-action' => 'activate',
),
admin_url( 'admin.php?page=jetpack' )
),
'jetpack-backup-install'
);
}
/**
* A special filter used in the CTA of a JITM offering to install the Jetpack Boost plugin.
*
* @return string The new CTA
*/
public static function jitm_jetpack_boost_install() {
return wp_nonce_url(
add_query_arg(
array(
'jetpack-boost-action' => 'install',
),
admin_url( 'admin.php?page=jetpack' )
),
'jetpack-boost-install'
);
}
/**
* A special filter used in the CTA of a JITM offering to activate the Jetpack Boost plugin.
*
* @return string The new CTA
*/
public static function jitm_jetpack_boost_activate() {
return wp_nonce_url(
add_query_arg(
array(
'jetpack-boost-action' => 'activate',
),
admin_url( 'admin.php?page=jetpack' )
),
'jetpack-boost-install'
);
}
/**
* This is an entire admin notice dedicated to messaging and handling of the case where a user is trying to delete
* the connection owner.
*/
public function delete_user_update_connection_owner_notice() {
global $current_screen;
/*
* phpcs:disable WordPress.Security.NonceVerification.Recommended
*
* This function is firing within wp-admin and checks (below) if it is in the midst of a deletion on the users
* page. Nonce will be already checked by WordPress, so we do not need to check ourselves.
*/
if ( ! isset( $current_screen->base ) || 'users' !== $current_screen->base ) {
return;
}
if ( ! isset( $_REQUEST['action'] ) || 'delete' !== $_REQUEST['action'] ) {
return;
}
// Get connection owner or bail.
$connection_manager = new Manager();
$connection_owner_id = $connection_manager->get_connection_owner_id();
if ( ! $connection_owner_id ) {
return;
}
$connection_owner_userdata = get_userdata( $connection_owner_id );
// Bail if we're not trying to delete connection owner.
$user_ids_to_delete = array();
if ( isset( $_REQUEST['users'] ) ) {
$user_ids_to_delete = array_map( 'sanitize_text_field', wp_unslash( $_REQUEST['users'] ) );
} elseif ( isset( $_REQUEST['user'] ) ) {
$user_ids_to_delete[] = sanitize_text_field( wp_unslash( $_REQUEST['user'] ) );
}
// phpcs:enable
$user_ids_to_delete = array_map( 'absint', $user_ids_to_delete );
$deleting_connection_owner = in_array( $connection_owner_id, (array) $user_ids_to_delete, true );
if ( ! $deleting_connection_owner ) {
return;
}
// Bail if they're trying to delete themselves to avoid confusion.
if ( get_current_user_id() === $connection_owner_id ) {
return;
}
// Track it!
if ( method_exists( $this->tracking, 'record_user_event' ) ) {
$this->tracking->record_user_event( 'delete_connection_owner_notice_view' );
}
$connected_admins = $connection_manager->get_connected_users( 'jetpack_disconnect' );
$user = is_a( $connection_owner_userdata, 'WP_User' ) ? esc_html( $connection_owner_userdata->data->user_login ) : '';
echo "<div class='notice notice-warning' id='jetpack-notice-switch-connection-owner'>";
echo '<h2>' . esc_html__( 'Important notice about your Jetpack connection:', 'jetpack-jitm' ) . '</h2>';
echo '<p>' . sprintf(
/* translators: WordPress User, if available. */
esc_html__( 'Warning! You are about to delete the Jetpack connection owner (%s) for this site, which may cause some of your Jetpack features to stop working.', 'jetpack-jitm' ),
esc_html( $user )
) . '</p>';
if ( ! empty( $connected_admins ) && count( $connected_admins ) > 1 ) {
echo '<form id="jp-switch-connection-owner" action="" method="post">';
echo "<label for='owner'>" . esc_html__( 'You can choose to transfer connection ownership to one of these already-connected admins:', 'jetpack-jitm' ) . ' </label>';
$connected_admin_ids = array_map(
function ( $connected_admin ) {
return $connected_admin->ID;
},
$connected_admins
);
wp_dropdown_users(
array(
'name' => 'owner',
'include' => array_diff( $connected_admin_ids, array( $connection_owner_id ) ),
'show' => 'display_name_with_login',
)
);
echo '<p>';
submit_button( esc_html__( 'Set new connection owner', 'jetpack-jitm' ), 'primary', 'jp-switch-connection-owner-submit', false );
echo '</p>';
echo "<div id='jp-switch-user-results'></div>";
echo '</form>';
?>
<script type="text/javascript">
jQuery( document ).ready( function( $ ) {
$( '#jp-switch-connection-owner' ).on( 'submit', function( e ) {
var formData = $( this ).serialize();
var submitBtn = document.getElementById( 'jp-switch-connection-owner-submit' );
var results = document.getElementById( 'jp-switch-user-results' );
submitBtn.disabled = true;
$.ajax( {
type : "POST",
url : "<?php echo esc_url( get_rest_url() . 'jetpack/v4/connection/owner' ); ?>",
data : formData,
headers : {
'X-WP-Nonce': "<?php echo esc_js( wp_create_nonce( 'wp_rest' ) ); ?>",
},
success: function() {
results.innerHTML = "<?php esc_html_e( 'Success!', 'jetpack-jitm' ); ?>";
setTimeout( function() {
$( '#jetpack-notice-switch-connection-owner' ).hide( 'slow' );
}, 1000 );
}
} ).done( function() {
submitBtn.disabled = false;
} );
e.preventDefault();
return false;
} );
} );
</script>
<?php
} else {
echo '<p>' . esc_html__( 'Every Jetpack site needs at least one connected admin for the features to work properly. Please connect to your WordPress.com account via the button below. Once you connect, you may refresh this page to see an option to change the connection owner.', 'jetpack-jitm' ) . '</p>';
$connect_url = $connection_manager->get_authorization_url();
$connect_url = add_query_arg( 'from', 'delete_connection_owner_notice', $connect_url );
echo "<a href='" . esc_url( $connect_url ) . "' target='_blank' rel='noopener noreferrer' class='button-primary'>" . esc_html__( 'Connect to WordPress.com', 'jetpack-jitm' ) . '</a>';
}
echo '<p>';
printf(
wp_kses(
/* translators: URL to Jetpack support doc regarding the primary user. */
__( "<a href='%s' target='_blank' rel='noopener noreferrer'>Learn more</a> about the connection owner and what will break if you do not have one.", 'jetpack-jitm' ),
array(
'a' => array(
'href' => true,
'target' => true,
'rel' => true,
),
)
),
esc_url( Redirect::get_url( 'jetpack-support-primary-user' ) )
);
echo '</p>';
echo '<p>';
printf(
wp_kses(
/* translators: URL to contact Jetpack support. */
__( 'As always, feel free to <a href="%s" target="_blank" rel="noopener noreferrer">contact our support team</a> if you have any questions.', 'jetpack-jitm' ),
array(
'a' => array(
'href' => true,
'target' => true,
'rel' => true,
),
)
),
esc_url( Redirect::get_url( 'jetpack-contact-support' ) )
);
echo '</p>';
echo '</div>';
}
/**
* Dismisses a JITM feature class so that it will no longer be shown.
*
* @param string $id The id of the JITM that was dismissed.
* @param string $feature_class The feature class of the JITM that was dismissed.
*
* @return bool Always true.
*/
public function dismiss( $id, $feature_class ) {
$this->tracking->record_user_event(
'jitm_dismiss_client',
array(
'jitm_id' => $id,
'feature_class' => $feature_class,
)
);
$this->save_dismiss( $feature_class );
return true;
}
/**
* Asks the wpcom API for the current message to display keyed on query string and message path
*
* @param string $message_path The message path to ask for.
* @param string $query The query string originally from the front end.
* @param bool $full_jp_logo_exists If there is a full Jetpack logo already on the page.
*
* @return array The JITM's to show, or an empty array if there is nothing to show
*/
public function get_messages( $message_path, $query, $full_jp_logo_exists ) {
// WooCommerce Services.
add_filter( 'jitm_woocommerce_services_msg', array( $this, 'jitm_woocommerce_services_msg' ) );
add_filter( 'jitm_jetpack_woo_services_install', array( $this, 'jitm_jetpack_woo_services_install' ) );
add_filter( 'jitm_jetpack_woo_services_activate', array( $this, 'jitm_jetpack_woo_services_activate' ) );
// Creative Mail.
add_filter( 'jitm_jetpack_creative_mail_install', array( $this, 'jitm_jetpack_creative_mail_install' ) );
add_filter( 'jitm_jetpack_creative_mail_activate', array( $this, 'jitm_jetpack_creative_mail_activate' ) );
// Jetpack Backup.
add_filter( 'jitm_jetpack_backup_install', array( $this, 'jitm_jetpack_backup_install' ) );
add_filter( 'jitm_jetpack_backup_activate', array( $this, 'jitm_jetpack_backup_activate' ) );
// Jetpack Boost.
add_filter( 'jitm_jetpack_boost_install', array( $this, 'jitm_jetpack_boost_install' ) );
add_filter( 'jitm_jetpack_boost_activate', array( $this, 'jitm_jetpack_boost_activate' ) );
$user = wp_get_current_user();
// Unauthenticated or invalid requests just bail.
if ( ! $user ) {
return array();
}
$user_roles = implode( ',', $user->roles );
$site_id = \Jetpack_Options::get_option( 'id' );
// Build our jitm request.
$path = add_query_arg(
array(
'external_user_id' => urlencode_deep( $user->ID ),
'user_roles' => urlencode_deep( $user_roles ),
'query_string' => urlencode_deep( $query ),
'mobile_browser' => Device_Detection::is_smartphone() ? 1 : 0,
'_locale' => get_user_locale(),
),
sprintf( '/sites/%d/jitm/%s', $site_id, $message_path )
);
// Attempt to get from cache.
$envelopes = get_transient( 'jetpack_jitm_' . substr( md5( $path ), 0, 31 ) );
// If something is in the cache and it was put in the cache after the last sync we care about, use it.
$use_cache = false;
/**
* Filter to turn off jitm caching
*
* @since 1.1.0
* @since-jetpack 5.4.0
*
* @param bool true Whether to cache just in time messages
*/
if ( apply_filters( 'jetpack_just_in_time_msg_cache', true ) ) {
$use_cache = true;
}
if ( $use_cache ) {
$last_sync = (int) get_transient( 'jetpack_last_plugin_sync' );
$from_cache = $envelopes && $last_sync > 0 && $last_sync < $envelopes['last_response_time'];
} else {
$from_cache = false;
}
// Otherwise, ask again.
if ( ! $from_cache ) {
$wpcom_response = Client::wpcom_json_api_request_as_blog(
$path,
'2',
array(
'user_id' => $user->ID,
'user_roles' => implode( ',', $user->roles ),
),
null,
'wpcom'
);
// silently fail...might be helpful to track it?
if ( is_wp_error( $wpcom_response ) ) {
return array();
}
$envelopes = json_decode( $wpcom_response['body'] );
if ( ! is_array( $envelopes ) ) {
return array();
}
$expiration = isset( $envelopes[0] ) ? $envelopes[0]->ttl : 300;
// Do not cache if expiration is 0 or we're not using the cache.
if ( 0 !== $expiration && $use_cache ) {
$envelopes['last_response_time'] = time();
set_transient( 'jetpack_jitm_' . substr( md5( $path ), 0, 31 ), $envelopes, $expiration );
}
}
$hidden_jitms = \Jetpack_Options::get_option( 'hide_jitm' );
unset( $envelopes['last_response_time'] );
/**
* Allow adding your own custom JITMs after a set of JITMs has been received.
*
* @since 1.1.0
* @since-jetpack 6.9.0
* @since-jetpack 8.3.0 - Added Message path.
*
* @param array $envelopes array of existing JITMs.
* @param string $message_path The message path to ask for.
*/
$envelopes = apply_filters( 'jetpack_jitm_received_envelopes', $envelopes, $message_path );
foreach ( $envelopes as $idx => &$envelope ) {
$dismissed_feature = isset( $hidden_jitms[ $envelope->feature_class ] ) && is_array( $hidden_jitms[ $envelope->feature_class ] ) ? $hidden_jitms[ $envelope->feature_class ] : null;
// If the this feature class has been dismissed and the request has not passed the ttl, skip it as it's been dismissed.
if ( is_array( $dismissed_feature ) && ( time() - $dismissed_feature['last_dismissal'] < $envelope->expires || $dismissed_feature['number'] >= $envelope->max_dismissal ) ) {
unset( $envelopes[ $idx ] );
continue;
}
$this->tracking->record_user_event(
'jitm_view_client',
array(
'jitm_id' => $envelope->id,
)
);
$url_params = array(
'u' => $user->ID,
);
// Get affiliate code and add it to the array of URL parameters.
$aff = Partner::init()->get_partner_code( Partner::AFFILIATE_CODE );
if ( '' !== $aff ) {
$url_params['aff'] = $aff;
}
// Check if the current user has connected their WP.com account
// and if not add this information to the the array of URL parameters.
if ( ! ( new Manager() )->is_user_connected( $user->ID ) ) {
$url_params['query'] = 'unlinked=1';
}
$envelope->url = esc_url( Redirect::get_url( "jitm-$envelope->id", $url_params ) );
$stats = new A8c_Mc_Stats();
$envelope->jitm_stats_url = $stats->build_stats_url( array( 'x_jetpack-jitm' => $envelope->id ) );
// phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
// $CTA is not valid per PHPCS, but it is part of the return from WordPress.com, so allowing.
if ( $envelope->CTA->hook ) {
$envelope->url = apply_filters( 'jitm_' . $envelope->CTA->hook, $envelope->url );
unset( $envelope->CTA->hook );
}
// phpcs:enable
if ( isset( $envelope->content->hook ) ) {
$envelope->content = apply_filters( 'jitm_' . $envelope->content->hook, $envelope->content );
unset( $envelope->content->hook );
}
// No point in showing an empty message.
if ( empty( $envelope->content->message ) ) {
unset( $envelopes[ $idx ] );
continue;
}
$envelope->content->icon = $this->generate_icon( $envelope->content->icon, $full_jp_logo_exists );
$stats->add( 'jitm', $envelope->id . '-viewed' );
$stats->do_server_side_stats();
}
return $envelopes;
}
}

View File

@ -0,0 +1,171 @@
<?php
/**
* Jetpack's Pre-Connection JITM class.
*
* @package automattic/jetpack-jitm
*/
namespace Automattic\Jetpack\JITMS;
/**
* Jetpack pre-connection just in time messaging through out the admin.
*/
class Pre_Connection_JITM extends JITM {
/**
* Filters and formats the messages for the client-side JS renderer
*
* @param string $message_path Current message path.
*
* @return array Formatted messages.
*/
private function filter_messages( $message_path ) {
/**
* Allows filtering of the pre-connection JITMs.
*
* This filter allows plugins to add pre-connection JITMs that will be
* displayed by the JITM package.
*
* @since 1.14.1
*
* @param array An array of pre-connection messages.
*/
$messages = apply_filters( 'jetpack_pre_connection_jitms', array() );
$messages = $this->validate_messages( $messages );
$formatted_messages = array();
foreach ( $messages as $message ) {
if ( ! preg_match( $message['message_path'], $message_path ) ) {
continue;
}
$obj = new \stdClass();
$obj->CTA = array( // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
'message' => $message['button_caption'],
'newWindow' => false,
);
$obj->url = $message['button_link'];
$obj->id = $message['id'];
$obj->is_dismissible = true;
$obj->content = array(
'message' => $message['message'],
'description' => $message['description'],
'list' => array(),
'icon' => $this->get_message_icon( $message ),
);
$formatted_messages[] = $obj;
}
return $formatted_messages;
}
/**
* Validates that each of the messages contains all of the required keys:
* - id
* - message_path
* - message
* - description
* - button_link
* - button_caption
*
* @param array $messages An array of JITM messages.
*
* @return array An array of JITM messages that contain all of the required keys.
*/
private function validate_messages( $messages ) {
if ( ! is_array( $messages ) ) {
return array();
}
$expected_keys = array_flip( array( 'id', 'message_path', 'message', 'description', 'button_link', 'button_caption' ) );
foreach ( $messages as $index => $message ) {
if ( count( array_intersect_key( $expected_keys, $message ) ) !== count( $expected_keys ) ) {
// Remove any messages that are missing expected keys.
unset( $messages[ $index ] );
}
}
return $messages;
}
/**
* Get the icon for the message.
*
* The message may contain an 'icon' key. If the value of the 'icon' key matches a supported icon (or empty string), the value is used.
* If the message does not contain an icon key or if the value does not match a supported icon, the Jetpack icon is used by default.
*
* @param array $message A pre-connection JITM.
*
* @return string The icon to use in the JITM.
*/
private function get_message_icon( $message ) {
// Default to the Jetpack icon.
$icon = 'jetpack';
if ( ! isset( $message['icon'] ) ) {
return $icon;
}
$supported_icons = $this->get_supported_icons();
if ( in_array( $message['icon'], $supported_icons, true ) ) {
// Only use the message icon if it's a supported icon or an empty string (for no icon).
$icon = $message['icon'];
}
return $icon;
}
/**
* Retrieve the current message to display keyed on query string and message path
*
* @param string $message_path The message path to ask for.
* @param string $query The query string originally from the front end. Unused in this subclass.
* @param bool $full_jp_logo_exists If there is a full Jetpack logo already on the page.
*
* @return array The JITMs to show, or an empty array if there is nothing to show
*/
public function get_messages( $message_path, $query, $full_jp_logo_exists ) {
if ( ! current_user_can( 'install_plugins' ) ) {
return array();
}
$messages = $this->filter_messages( $message_path );
if ( empty( $messages ) ) {
return array();
}
$hidden_jitms = \Jetpack_Options::get_option( 'hide_jitm' );
foreach ( $messages as $idx => &$envelope ) {
$dismissed_feature = isset( $hidden_jitms[ 'pre-connection-' . $envelope->id ] ) &&
is_array( $hidden_jitms[ 'pre-connection-' . $envelope->id ] ) ? $hidden_jitms[ 'pre-connection-' . $envelope->id ] : null;
if ( is_array( $dismissed_feature ) ) {
unset( $messages[ $idx ] );
continue;
}
$envelope->content['icon'] = $this->generate_icon( $envelope->content['icon'], $full_jp_logo_exists );
}
return $messages;
}
/**
* Dismisses a JITM ID so that it will no longer be shown.
*
* @param string $id The id of the JITM that was dismissed.
*
* @return bool Always true
*/
public function dismiss( $id ) {
$this->save_dismiss( 'pre-connection-' . $id );
return true;
}
}

View File

@ -0,0 +1,92 @@
<?php
/**
* JITM's REST API Endpoints
*
* @package automattic/jetpack-jitm
*/
namespace Automattic\Jetpack\JITMS;
use Automattic\Jetpack\Connection\REST_Connector;
use WP_REST_Server;
/**
* Register the JITM's REST API Endpoints and their callbacks.
*/
class Rest_Api_Endpoints {
/**
* Declare the JITM's REST API endpoints.
*/
public static function register_endpoints() {
register_rest_route(
'jetpack/v4',
'/jitm',
array(
'methods' => WP_REST_Server::READABLE,
'callback' => __CLASS__ . '::get_jitm_message',
'permission_callback' => '__return_true',
)
);
register_rest_route(
'jetpack/v4',
'/jitm',
array(
'methods' => WP_REST_Server::CREATABLE,
'callback' => __CLASS__ . '::delete_jitm_message',
'permission_callback' => __CLASS__ . '::delete_jitm_message_permission_callback',
)
);
}
/**
* Asks for a jitm, unless they've been disabled, in which case it returns an empty array
*
* @param WP_REST_Request $request The request object.
*
* @return array An array of jitms
*/
public static function get_jitm_message( $request ) {
$jitm = JITM::get_instance();
if ( ! $jitm->jitms_enabled() ) {
return array();
}
return $jitm->get_messages( $request['message_path'], urldecode_deep( $request['query'] ), 'true' === $request['full_jp_logo_exists'] ? true : false );
}
/**
* Dismisses a jitm.
*
* @param WP_REST_Request $request The request object.
*
* @return bool Always True
*/
public static function delete_jitm_message( $request ) {
$jitm = JITM::get_instance();
if ( ! $jitm->jitms_enabled() ) {
return true;
}
return $jitm->dismiss( $request['id'], $request['feature_class'] );
}
/**
* Verify that the user can dismiss JITM messages.
*
* @return bool|WP_Error True if user is able to dismiss JITM messages.
*/
public static function delete_jitm_message_permission_callback() {
if ( current_user_can( 'read' ) ) {
return true;
}
return new \WP_Error( 'invalid_user_permission_jetpack_delete_jitm_message', REST_Connector::get_user_permissions_error_msg(), array( 'status' => rest_authorization_required_code() ) );
}
}

View File

@ -0,0 +1,494 @@
// Just in Time Messaging - message prompts
// TODO: Switch to using the `@automattic/jetpack-base-styles` package when its ready.
@import '../../plugins/jetpack/_inc/client/scss/functions/rem';
@import '../../plugins/jetpack/_inc/client/scss/variables/colors';
@import '../../plugins/jetpack/_inc/client/scss/mixins/breakpoints';
@import '../../plugins/jetpack/_inc/client/scss/calypso-colors';
@mixin clear-fix {
&:after {
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
}
@mixin jitm-banner-color( $color ) {
border-left-color: $color;
.jitm-banner__icon {
color: $color;
}
.jitm-banner__icon-circle {
background-color: $color;
}
}
// New JITMS - modified calypso banner styles
$blue-grey-light: #f6f7f7;
$blue-medium-dark: #2271b1;
.jitm-button {
background: $blue-grey-light;
border-color: $blue-medium-dark;
border-style: solid;
border-width: 1px;
color: $blue-medium-dark;
cursor: pointer;
display: inline-block;
margin: 0;
outline: 0;
overflow: hidden;
font-size: 14px;
text-overflow: ellipsis;
text-decoration: none;
vertical-align: top;
box-sizing: border-box;
font-size: 14px;
border-radius: 4px;
padding: 7px 14px 9px;
-webkit-appearance: none;
appearance: none;
text-align: center;
min-width: 90px;
&:hover {
background: #f0f0f1;
border-color: $blue-grey-dark;
color: $blue-grey-dark;
}
&[disabled],
&:disabled {
color: lighten( $gray, 30% );
background: $white;
border-color: lighten( $gray, 30% );
cursor: default;
}
&:focus {
background: $white;
border-color: $blue-medium-dark;
box-shadow: 0 0 0 1px $blue-medium-dark;
}
&.is-compact {
padding: 7px;
font-size: 11px;
line-height: 1;
text-transform: uppercase;
white-space: nowrap;
&:disabled {
color: lighten( $gray, 30% );
}
.gridicon {
top: 4px;
margin-top: -8px;
}
// Make the left margin of the small plus icon visually less huge
.gridicons-plus-small {
margin-left: -4px;
}
// Reset the left margin if the button contains only the plus icon
.gridicons-plus-small:last-of-type {
margin-left: 0;
}
// Make plus icon nudged closer to adjacent icons for add-people and add-plugin type buttons
.gridicons-plus-small + .gridicon {
margin-left: -4px;
}
}
&.hidden {
display: none;
}
}
// Primary buttons
.jitm-button.is-primary {
background: $blue-medium;
border-color: $blue-medium;
color: $white;
&:hover,
&:focus {
border-color: $blue-medium-dark;
background: $blue-medium-dark;
color: $white;
}
&:focus {
box-shadow:
0 0 0 1px $white,
0 0 0 3px $blue-medium-dark;
}
&[disabled],
&:disabled {
background: tint( $blue-light, 50% );
border-color: tint( $blue-wordpress, 55% );
color: $white;
}
&.is-compact {
color: $white;
white-space: nowrap;
}
}
.jitm-card {
display: block;
clear: both;
position: relative;
margin: rem( 48px ) rem( 20px ) 0 auto;
padding: rem( 16px );
box-sizing: border-box;
background: $white;
box-shadow:
0 0 0 1px $light-gray-700,
0 1px 1px 1px rgba(0,0,0,.04);
@include clear-fix;
@include breakpoint( ">480px" ) {
margin-bottom: rem( 16px );
padding: rem( 24px );
}
// Compact Card
&.is-compact {
margin-bottom: rem( 1px );
@include breakpoint( ">480px" ) {
margin-bottom: 1px;
padding: rem( 16px ) rem( 24px );
}
}
&.is-card-link {
padding-right: rem( 48px );
}
}
// Minor adjustments for the display in My Jetpack.
.my-jetpack-jitm-card {
.jitm-card {
margin-right: 0;
margin-bottom: 0;
}
}
// if JITM appears directly below WordPress "help" menu adjust margins
#screen-meta-links+.jitm-card {
margin: rem( 40px ) 1.5385em 0 auto;
}
// if JITM appears directly below WordPress hello dolly adjust margins
#dolly+.jitm-card {
margin: 3rem 1rem 0 auto;
}
// remove right margin for jitms in the editor
.post-php .jitm-card {
margin-right: 0;
}
// if JITM appears inside of the jetpack dashboard adjust margins
.jp-lower .jitm-card {
margin: 0 0 rem( 24px );
}
.jitm-banner.jitm-card {
border-left: 4px solid;
display: flex;
padding: rem( 12px ) rem( 6px ) rem( 12px ) rem( 12px );
position: relative;
z-index: 2;
@include breakpoint( "<480px" ) {
display: flex;
padding: rem( 12px );
flex-direction: column;
}
&.is-card-link {
padding: rem( 12px ) rem( 48px ) rem( 12px ) rem( 16px );
}
&.is-dismissible {
padding-right: rem( 48px );
}
@include jitm-banner-color( $alert-green );
&.is-upgrade-personal {
@include jitm-banner-color( $alert-yellow );
}
&.is-upgrade-premium {
@include jitm-banner-color( $alert-green );
}
&.is-upgrade-business,
&.woo-jitm {
@include jitm-banner-color( $alert-purple );
}
.jitm-card__link-indicator {
align-items: center;
color: $blue-wordpress;
display: flex;
}
&:hover {
transition: all 100ms ease-in-out;
&.is-card-link {
box-shadow: 0 0 0 1px $gray, 0 2px 4px lighten( $gray, 20% );
}
.jitm-card__link-indicator {
color: $blue-dark;
}
}
@include breakpoint( ">480px" ) {
padding: rem( 12px ) rem( 16px );
&.is-dismissible {
padding-right: rem( 16px );
}
}
}
.jitm-banner__buttons_container {
display: grid;
height: 50%;
margin-top: auto;
margin-bottom: auto;
@include breakpoint( ">480px" ) {
display: flex;
}
}
.jitm-banner__icons {
display: flex;
.jitm-banner__icon,
.jitm-banner__icon-circle {
border-radius: 50%;
flex-shrink: 0;
height: rem( 24px );
width: rem( 24px );
margin-right: rem( 16px );
margin-top: rem( -2px );
text-align: center;
top: rem( 4px );
}
.jitm-banner__icon {
align-self: center;
color: $white;
display: block;
}
.jitm-banner__icon-circle {
color: white;
display: none;
padding: rem( 3px ) rem( 4px ) rem( 4px ) rem( 3px );
}
@include breakpoint( ">480px" ) {
align-items: center;
.jitm-banner__icon {
display: none;
}
.jitm-banner__icon-circle {
display: block;
}
}
}
.jitm-banner__icon-plan {
display: flex;
margin-right: rem( 16px );
.dops-plan-icon {
height: rem( 32px );
width: rem( 32px );
}
.jp-emblem {
position: relative;
top: rem( 2px );
@include breakpoint( "<480px" ) {
margin-bottom: rem( 12px );
}
svg {
height: rem( 32px );
width: rem( 32px );
fill: $green-primary;
}
.jitm-jp-logo {
height: inherit;
width: 6rem;
fill: inherit;
}
}
@include breakpoint( ">480px" ) {
align-items: center;
}
@include breakpoint( "<960px" ) {
margin-bottom: 10px;
}
}
.jitm-banner__content {
align-items: center;
display: flex;
flex-grow: 1;
flex-wrap: wrap;
@include breakpoint( "<480px" ) {
margin-right: 0;
}
@include breakpoint( ">480px" ) {
flex-wrap: nowrap;
}
@include breakpoint( "<960px" ) {
display: grid;
margin-right: 5px;
}
}
.jitm-banner__info {
flex-grow: 1;
line-height: 1.4;
@include breakpoint( ">480px" ) {
flex-basis: 50%;
}
@include breakpoint( ">960px" ) {
flex-basis: 70%;
}
.jitm-banner__title,
.jitm-banner__description {
color: $gray-dark;
}
.jitm-banner__title {
font-size: 14px;
font-weight: 500;
}
.jitm-banner__description {
font-size: rem( 12px );
line-height: 1.5;
margin-top: rem( 6px );
}
.banner__list {
font-size: 12px;
list-style: none;
margin: 10px 0;
li {
margin: 6px 0;
.gridicon {
fill: $gray;
display: inline;
margin-right: 12px;
vertical-align: bottom;
}
}
}
}
.jitm-banner__action {
align-self: center;
font-size: rem( 12px );
margin: rem( 8px ) 0 0;
text-align: left;
width: 100%;
.jitm-banner__prices {
display: flex;
justify-content: flex-start;
.dops-plan-price {
margin-bottom: 0;
}
.dops-plan-price.is-discounted,
.dops-plan-price.is-discounted .dops-plan-price__currency-symbol {
color: $gray-dark;
}
.has-call-to-action & .dops-plan-price {
margin-bottom: rem( 8px );
}
}
@include breakpoint( "<480px" ) {
margin-top: 1rem;
}
@include breakpoint( ">480px" ) {
margin: 0 rem( 4px ) 0 rem( 8px );
text-align: center;
width: auto;
.is-dismissible {
margin-top: rem( 40px );
}
.jitm-banner__prices {
justify-content: flex-end;
text-align: right;
}
}
}
.jitm-banner__dismiss {
display: block;
text-decoration: none;
line-height: .5;
margin-top: auto;
margin-bottom: auto;
&:before {
color: darken($gray, 20%);
font: 400 16px/1 dashicons;
content: '\f158';
}
@include breakpoint( ">660px" ) {
margin-right: rem( -8px );
}
@include breakpoint( "<480px" ) {
position: absolute;
top: 0;
right: 0;
display: flex;
justify-content: center;
align-items: center;
margin: 0;
// Minimum touch area
width: 48px;
height: 48px;
}
}
.jitm-banner__action + .jitm-banner__dismiss {
margin-left: rem( 10px );
}
#dolly + .jitm-card {
margin: 3rem 1rem 0 auto;
}

View File

@ -0,0 +1,269 @@
import '../css/jetpack-admin-jitm.scss';
jQuery( document ).ready( function ( $ ) {
var templates = {
default: function ( envelope ) {
var html =
'<div class="jitm-card jitm-banner ' +
( envelope.CTA.message ? 'has-call-to-action' : '' ) +
' is-upgrade-premium ' +
envelope.content.classes +
'" data-stats_url="' +
envelope.jitm_stats_url +
'">';
html += '<div class="jitm-banner__content">';
html += '<div class="jitm-banner__icon-plan">' + envelope.content.icon + '</div>';
html += '<div class="jitm-banner__info">';
html += '<div class="jitm-banner__title">' + envelope.content.message + '</div>';
if ( envelope.content.description && envelope.content.description !== '' ) {
html += '<div class="jitm-banner__description">' + envelope.content.description;
if ( envelope.content.list.length > 0 ) {
html += '<ul class="banner__list">';
for ( var i = 0; i < envelope.content.list.length; i++ ) {
var text = envelope.content.list[ i ].item;
if ( envelope.content.list[ i ].url ) {
text =
'<a href="' +
envelope.content.list[ i ].url +
'" target="_blank" rel="noopener noreferrer" data-module="' +
envelope.feature_class +
'" data-jptracks-name="nudge_item_click" data-jptracks-prop="jitm-' +
envelope.id +
'">' +
text +
'</a>';
}
html +=
'<li>' +
'<svg class="gridicon gridicons-checkmark" height="16" width="16" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g>' +
'<path d="M9 19.414l-6.707-6.707 1.414-1.414L9 16.586 20.293 5.293l1.414 1.414" /></g></svg>' +
text +
'</li>';
}
}
html += '</div>';
}
html += '</div>';
html += '</div>';
html += '<div class="jitm-banner__buttons_container">';
if ( envelope.activate_module ) {
html += '<div class="jitm-banner__action" id="jitm-banner__activate">';
html +=
'<a href="#" data-module="' +
envelope.activate_module +
'" type="button" class="jitm-button is-compact is-primary jptracks" data-jptracks-name="nudge_click" data-jptracks-prop="jitm-' +
envelope.id +
'-activate_module">' +
window.jitm_config.activate_module_text +
'</a>';
html += '</div>';
}
if ( envelope.CTA.message ) {
var ctaClasses = 'jitm-button is-compact jptracks';
if ( envelope.CTA.primary && null === envelope.activate_module ) {
ctaClasses += ' is-primary';
}
var ajaxAction = envelope.CTA.ajax_action;
html += '<div class="jitm-banner__action">';
html +=
'<a href="' +
( envelope.CTA.hasOwnProperty( 'link' ) && envelope.CTA.link.length
? envelope.CTA.link
: envelope.url ) +
'" target="' +
( envelope.CTA.newWindow === false || ajaxAction ? '_self' : '_blank' ) +
'" rel="noopener noreferrer" title="' +
envelope.CTA.message +
'" data-module="' +
envelope.feature_class +
'" type="button" class="' +
ctaClasses +
'" data-jptracks-name="nudge_click" data-jptracks-prop="jitm-' +
envelope.id +
'" ' +
( ajaxAction ? 'data-ajax-action="' + ajaxAction + '"' : '' ) +
'>' +
envelope.CTA.message +
'</a>';
html += '</div>';
}
html += '</div>';
if ( envelope.is_dismissible ) {
html +=
'<a href="#" data-module="' +
envelope.feature_class +
'" class="jitm-banner__dismiss"></a>';
}
html += '</div>';
return $( html );
},
};
var setJITMContent = function ( $el, response, redirect ) {
var template;
var render = function ( $my_template ) {
return function ( e ) {
e.preventDefault();
$my_template.hide();
$.ajax( {
url: window.jitm_config.api_root + 'jetpack/v4/jitm',
method: 'POST', // using DELETE without permalinks is broken in default nginx configuration
beforeSend: function ( xhr ) {
xhr.setRequestHeader( 'X-WP-Nonce', window.jitm_config.nonce );
},
data: {
id: response.id,
feature_class: response.feature_class,
},
} );
};
};
template = response.template;
// if we don't have a template for this version, just use the default template
if ( ! template || ! templates[ template ] ) {
template = 'default';
}
response.url = response.url + '&redirect=' + redirect;
var $template = templates[ template ]( response );
$template.find( '.jitm-banner__dismiss' ).on( 'click', render( $template ) );
if ( $( '#jp-admin-notices' ).length > 0 ) {
// Add to Jetpack notices within the Jetpack settings app.
$el.innerHTML = $template;
// If we already have a message, replace it.
if ( $( '#jp-admin-notices' ).find( '.jitm-card' ) ) {
$( '.jitm-card' ).replaceWith( $template );
}
// No existing JITM? Add ours to the top of the Jetpack admin notices.
$template.prependTo( $( '#jp-admin-notices' ) );
} else {
// Replace placeholder div on other pages.
$el.replaceWith( $template );
}
// Handle Module activation button if it exists.
$template.find( '#jitm-banner__activate a' ).on( 'click', function () {
var $activate_button = $( this );
// Do not allow any requests if the button is disabled.
if ( $activate_button.attr( 'disabled' ) ) {
return false;
}
// Make request to activate module.
$.ajax( {
url:
window.jitm_config.api_root +
'jetpack/v4/module/' +
$activate_button.data( 'module' ) +
'/active',
method: 'POST',
beforeSend: function ( xhr ) {
xhr.setRequestHeader( 'X-WP-Nonce', $el.data( 'nonce' ) );
// Change the button status to disabled as the change is in progress.
$( '#jitm-banner__activate a' ).text( window.jitm_config.activating_module_text );
$( '#jitm-banner__activate a' ).attr( 'disabled', true );
},
} ).done( function () {
$( '#jitm-banner__activate a' ).text( window.jitm_config.activated_module_text );
$( '#jitm-banner__activate a' ).attr( 'disabled', true );
// Hide the JITM after 2 seconds.
setTimeout( function () {
$template.fadeOut( 'slow' );
}, 2000 );
} );
} );
// Handle CTA ajax actions.
$template.find( '.jitm-button[data-ajax-action]' ).on( 'click', function ( e ) {
e.preventDefault();
var button = $( this );
button.attr( 'disabled', true );
$.post( window.ajaxurl, {
action: button.data( 'ajax-action' ),
_nonce: $el.data( 'ajax-nonce' ),
} )
.done( function () {
$template.fadeOut( 'slow' );
} )
.fail( function () {
button.attr( 'disabled', false );
} );
return false;
} );
};
var reFetch = function () {
$( '.jetpack-jitm-message' ).each( function () {
var $el = $( this );
var message_path = $el.data( 'message-path' );
var query = $el.data( 'query' );
var redirect = $el.data( 'redirect' );
var hash = location.hash;
hash = hash.replace( /#\//, '_' );
if ( '_dashboard' !== hash ) {
message_path = message_path.replace(
'toplevel_page_jetpack',
'toplevel_page_jetpack' + hash
);
}
var full_jp_logo_exists = $( '.jetpack-logo__masthead' ).length ? true : false;
$.get( window.jitm_config.api_root + 'jetpack/v4/jitm', {
message_path: message_path,
query: query,
full_jp_logo_exists: full_jp_logo_exists,
_wpnonce: $el.data( 'nonce' ),
} ).then( function ( response ) {
if ( 'object' === typeof response && response[ '1' ] ) {
response = [ response[ '1' ] ];
}
// properly handle the case of an empty array or no content set
if ( 0 === response.length || ! response[ 0 ].content ) {
return;
}
// for now, always take the first response
setJITMContent( $el, response[ 0 ], redirect );
} );
} );
};
reFetch();
$( window ).on( 'hashchange', function ( e ) {
var newURL = e.originalEvent.newURL;
if ( newURL.indexOf( 'jetpack#/' ) >= 0 ) {
var jitm_card = document.querySelector( '.jitm-card' );
if ( jitm_card ) {
jitm_card.remove();
}
reFetch();
}
} );
} );