Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 57
0.00% covered (danger)
0.00%
0 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
Jetpack_Plugin_Compatibility
0.00% covered (danger)
0.00%
0 / 57
0.00% covered (danger)
0.00%
0 / 9
600
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 get_instance
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 check_plugin_compatibility
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
 incompatible_plugin_notices
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 disable_plugin_activate_link
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 disable_plugin_install_link
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
 find_incompatible_plugins
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 1
30
 get_disallowed_plugins
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
12
 get_plugin_status
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2/**
3 * Plugin compatibility file.
4 *
5 * @package wpcomsh
6 */
7
8/**
9 * Class Jetpack_Plugin_Compatibility.
10 */
11class Jetpack_Plugin_Compatibility {
12
13    /**
14     * Plugin file locations and html messaging in the format:
15     * array(
16     *   'example-plugin/example-plugin.php' => 'example-plugin interferes with Jetpack sync and has been disabled.'
17     * ),
18     * The html messaging is presented as a dismissible error admin notice when an unsupported plugin is deactivated.
19     *
20     * @var string[]
21     */
22    public $incompatible_plugins = array(
23        // "reset" - break/interfere with provided functionality.
24        'advanced-wp-reset/advanced-wp-reset.php'         => '"advanced-wp-reset" has been deactivated, it deletes data necessary to manage your site and is not supported on WordPress.com.',
25        'extended-wp-reset/extended-wp-reset.php'         => '"extended-wp-reset" has been deactivated, it interferes with site operation and is not supported on WordPress.com.',
26        'factory-reset/factory-reset.php'                 => '"factory-reset" has been deactivated, it deletes data necessary to manage your site and is not supported on WordPress.com.',
27        'file-manager/file-manager.php'                   => '"file-manager" has been deactivated, it deletes data necessary to manage your site and is not supported on WordPress.com.',
28        'hide-my-wp/index.php'                            => '"hide-my-wp" has been deactivated, it deletes data necessary to manage your site and is not supported on WordPress.com.',
29        'plugins-garbage-collector/plugins-garbage-collector.php' => '"plugins-garbage-collector" has been deactivated, it deletes data necessary to manage your site and is not supported on WordPress.com.',
30        'reset-wp/reset-wp.php'                           => '"reset-wp" has been deactivated, it deletes data necessary to manage your site and is not supported on WordPress.com.',
31        'reset/data_reset.php'                            => '"reset" has been deactivated, it deletes data necessary to manage your site and is not supported on WordPress.com.',
32        'ultimate-wp-reset/ultimate-wordpress-reset.php'  => '"ultimate-wp-reset" has been deactivated, it deletes data necessary to manage your site and is not supported on WordPress.com.',
33        'username-changer/class-username-changer.php'     => '"username-changer" has been deactivated, it deletes data necessary to manage your site and is not supported on WordPress.com.',
34        'vamtam-offline-jetpack/vamtam-offline-jetpack.php' => '"vamtam-offline-jetpack" has been deactivated, an active Jetpack Connection is required for your site to operate properly on WordPress.com.',
35        'wd-youtube/wd-youtube.php'                       => '"wd-youtube" has been deactivated, it interferes with site operation and is not supported on WordPress.com.',
36        'wordpress-reset/wordpress-reset.php'             => '"wordpress-reset" has been deactivated, it deletes data necessary to manage your site and is not supported on WordPress.com.',
37        'wp-automatic/wp-automatic.php'                   => '"wp-automatic" has been deactivated, it interferes with site operation and is not supported on WordPress.com.',
38        'wp-clone-by-wp-academy/wpclone.php'              => '"wp-clone-by-wp-academy" has been deactivated, it deletes data necessary to manage your site and is not supported on WordPress.com.',
39        'wp-file-manager/file_folder_manager.php'         => '"wp-file-manager" has been deactivated, it deletes data necessary to manage your site and is not supported on WordPress.com.',
40        'wp-uninstaller-by-azed/wp-uninstaller-by-azed.php' => '"wp-uninstaller-by-azed" is not supported on WordPress.com.',
41        'wpmu-database-reset/wpmu-database-reset.php'     => '"wpmu-database-reset" has been deactivated, it deletes data necessary to manage your site and is not supported on WordPress.com.',
42        'wps-hide-login/wps-hide-login.php'               => '"wps-hide-login" has been deactivated, it deletes data necessary to manage your site and is not supported on WordPress.com.',
43        'wp-downgrade/wp-downgrade.php'                   => '"wp-downgrade" has been deactivated, it deletes data necessary to manage your site and is not supported on WordPress.com.',
44
45        // Backup.
46        'backwpup/backwpup.php'                           => '"backwpup" has been deactivated, WordPress.com handles managing your site backups for you.',
47        'backwpup-pro/backwpup.php'                       => '"backwpup-pro" has been deactivated, WordPress.com handles managing your site backups for you.',
48        'jetpack-backup/jetpack-backup.php'               => '"jetpack-backup" has been deactivated, WordPress.com handles managing your site backups for you.',
49        'siteground-migrator/siteground-migrator.php'     => '"siteground-migrator" has been deactivated, WordPress.com handles managing your site backups for you.',
50        'wp-backitup/wp-backitup.php'                     => '"wp-backitup" has been deactivated, WordPress.com handles managing your site backups for you.',
51
52        // Caching/performance.
53        'breeze/breeze.php'                               => '"breeze" has been deactivated, WordPress.com automatically handles caching for your site.',
54        'cache-enabler/cache-enabler.php'                 => '"cache-enabler" has been deactivated, WordPress.com automatically handles caching for your site.',
55        'comet-cache/comet-cache.php'                     => '"comet-cache" has been deactivated, WordPress.com automatically handles caching for your site.',
56        'hyper-cache/plugin.php'                          => '"hyper-cache" has been deactivated, WordPress.com automatically handles caching for your site.',
57        'object-cache-pro/object-cache-pro.php'           => '"object-cache-pro" has been deactivated, WordPress.com automatically handles caching for your site.',
58        'powered-cache/powered-cache.php'                 => '"powered-cache" has been deactivated, WordPress.com automatically handles caching for your site.',
59        'redis-cache/redis-cache.php'                     => '"redis-cache" has been deactivated, WordPress.com automatically handles caching for your site.',
60        'sg-cachepress/sg-cachepress.php'                 => '"sg-cachepress" has been deactivated, WordPress.com automatically handles caching for your site.',
61        'w3-total-cache/w3-total-cache.php'               => '"w3-total-cache" has been deactivated, WordPress.com automatically handles caching for your site.',
62        'wp-fastest-cache/wpFastestCache.php'             => '"wp-fastest-cache" has been deactivated, WordPress.com automatically handles caching for your site.',
63        'wp-optimizer/wp-optimizer.php'                   => '"wp-optimizer" has been deactivated, "performance" related plugins may break your site or cause issues and are not supported on WordPress.com.',
64        'wp-scss/wp-scss.php'                             => '"wp-scss" has been deactivated, WordPress.com automatically handles caching for your site.',
65        'wp-speed-of-light/wp-speed-of-light.php'         => '"wp-speed-of-light" has been deactivated, WordPress.com automatically handles caching for your site.',
66        'wp-super-cache/wp-cache.php'                     => '"wp-super-cache" has been deactivated, WordPress.com automatically handles caching for your site.',
67
68        // SQL heavy.
69        'another-wordpress-classifieds-plugin/awpcp.php'  => '"another-wordpress-classifieds-plugin" has been deactivated, it is known to cause severe database performance issues and is not supported.',
70        'mass-pagesposts-creator/mass-pages-posts-creator.php' => '"mass-pagesposts-creator" has been deactivated, it is known to cause severe database performance issues and is not supported.',
71        'ol_scrapes/ol_scrapes.php'                       => '"ol_scrapes" has been deactivated, it is known to cause severe database performance issues and is not supported.',
72        'post-views-counter/post-views-counter.php'       => '"post-views-counter" has been deactivated, plugins that insert or update the database on page load can cause severe performance issues for your site and are not supported.',
73        'top-10/top-10.php'                               => '"top-10" has been deactivated, it is known to cause severe database performance issues and is not supported.',
74        'userpro/index.php'                               => '"userpro" has been deactivated, it is known to cause severe database performance issues and is not supported.',
75        'wp-inject/wpinject.php'                          => '"wp-inject" has been deactivated, it is known to cause severe database performance issues and is not supported.',
76        'wp-postviews/wp-postviews.php'                   => '"wp-postviews" has been deactivated, plugins that insert or update the database on page load can cause severe performance issues for your site and are not supported.',
77        'wp-rss-aggregator/wp-rss-aggregator.php'         => '"wp-rss-aggregator" has been deactivated, it is known to cause severe database performance issues and is not supported.',
78        'wp-rss-feed-to-post/wp-rss-feed-to-post.php'     => '"wp-rss-feed-to-post" has been deactivated, it is known to cause severe database performance issues and is not supported.',
79        'wp-rss-wordai/wp-rss-wordai.php'                 => '"wp-rss-wordai" has been deactivated, it is known to cause severe database performance issues and is not supported.',
80        'wp-session-manager/wp-session-manager.php'       => '"wp-session-manager" has been deactivated, it is known to cause severe database performance issues and is not supported.',
81        'wp-slimstat/wp-slimstat.php'                     => '"wp-slimstat" has been deactivated, plugins that insert or update the database on page load can cause severe performance issues for your site and are not supported.',
82        'WPRobot5/wprobot.php'                            => '"WPRobot5" has been deactivated, plugins that insert or update the database on page load can cause severe performance issues for your site and are not supported.',
83
84        // Security.
85        'antihacker/antihacker.php'                       => '"antihacker" has been deactivated, "security" related plugins may break your site or cause performance issues for your site and are not supported on WordPress.com.',
86        'disable-xml-rpc-api/disable-xml-rpc-api.php'     => '"disable-xml-rpc-api" has been deactivated, XML-RPC is required for your Jetpack Connection on WordPress.com.',
87        'manage-xml-rpc/manage-xml-rpc.php'               => '"manage-xml-rpc" has been deactivated, XML-RPC is required for your Jetpack Connection on WordPress.com.',
88        'one-click-ssl/ssl.php'                           => '"one-click-ssl" has been deactivated, because it is not supported on WordPress.com.',
89        'really-simple-ssl/rlrsssl-really-simple-ssl.php' => '"really-simple-ssl" is not supported on WordPress.com.',
90        'really-simple-ssl-pro/really-simple-ssl-pro.php' => '"really-simple-ssl-pro" is not supported on WordPress.com.',
91        'stopbadbots/stopbadbots.php'                     => '"stopbadbots" has been deactivated, "security" related plugins may break your site or cause performance issues for your site and are not supported on WordPress.com.',
92        'wee-remove-xmlrpc-methods/wee-remove-xmlrpc-methods.php' => '"wee-remove-xmlrpc-methods" has been deactivated, XML-RPC is required for your Jetpack Connection on WordPress.com.',
93        'wp-hide-security-enhancer/wp-hide.php'           => '"wp-hide-security-enhancer" has been deactivated, "security" related plugins may break your site or cause performance issues for your site and are not supported on WordPress.com.',
94        'wp-simple-firewall/wp-simple-firewall.php'       => '"wp-simple-firewall" has been deactivated, it deletes data necessary to manage your site and is not supported on WordPress.com.',
95        'wp-simple-firewall/icwp-wpsf.php'                => '"wp-simple-firewall" has been deactivated, it deletes data necessary to manage your site and is not supported on WordPress.com.',
96
97        // Spam.
98        'e-mail-broadcasting/e-mail-broadcasting.php'     => '"e-mail-broadcasting" has been deactivated, plugins that support sending e-mails in bulk are not supported on WordPress.com.',
99        'mailit/mailit.php'                               => '"mailit" has been deactivated, plugins that support sending e-mails in bulk are not supported on WordPress.com.',
100        'send-email-from-admin/send-email-from-admin.php' => '"send-email-from-admin" has been deactivated, plugins that support sending e-mails in bulk are not supported on WordPress.com.',
101
102        // Misc.
103        'adult-mass-photos-downloader/adult-mass-photos-downloader.php' => '"adult-mass-photos-downloader" is not supported on WordPress.com.',
104        'adult-mass-videos-embedder/adult-mass-videos-embedder.php' => '"adult-mass-videos-embedder" is not supported on WordPress.com.',
105        'automatic-video-posts/automatic-video-posts.php' => '"automatic-video-posts" is not supported on WordPress.com.',
106        'bwp-minify/bwp-minify.php'                       => '"bwp-minify" is not supported on WordPress.com.',
107        'db-access-adminer/db-access-adminer.php'         => '"db-access-adminer" is not supported on WordPress.com.',
108        'nginx-helper/nginx-helper.php'                   => '"nginx-helper" is not supported on WordPress.com.',
109        'p3/p3.php'                                       => '"p3" is not supported on WordPress.com.',
110        'pexlechris-adminer/pexlechris-adminer.php'       => '"pexlechris-adminer" is not supported on WordPress.com.',
111        'plugin-detective/plugin-detective.php'           => '"plugin-detective" is not supported on WordPress.com.',
112        'porn-embed/Porn-Embed.php'                       => '"porn-embed" is not supported on WordPress.com.',
113        'porn-videos-embed/porn-videos-embed.php'         => '"porn-videos-embed" is not supported on WordPress.com.',
114        'propellerads-official/propeller-ads.php'         => '"propellerads-official" is not supported on WordPress.com.',
115        'trafficzion/trafficzion.php'                     => '"trafficzion" is not supported on WordPress.com.',
116        'tubeace/tubeace.php'                             => '"tubeace" is not supported on WordPress.com.',
117        'woozone/plugin.php'                              => '"woozone" is not supported on WordPress.com.',
118        'wp-monero-miner-pro/monero-miner-pro.php'        => '"wp-monero-miner-pro" is not supported on WordPress.com.',
119        'wp-optimize-by-xtraffic/wp-optimize-by-xtraffic.php' => '"wp-optimize-by-xtraffic" is not supported on WordPress.com.',
120        'wpematico/wpematico.php'                         => '"wpematico" is not supported on WordPress.com.',
121        'wpstagecoach/wpstagecoach.php'                   => '"wpstagecoach" is not supported on WordPress.com.',
122        'yuzo-related-post/yuzo.php'                      => '"yuzo-related-post" is not supported on WordPress.com.',
123        'zapp-proxy-server/zapp-proxy-server.php'         => '"zapp-proxy-server" is not supported on WordPress.com.',
124    );
125
126    /**
127     * Admin notices.
128     *
129     * @var array
130     */
131    protected $admin_notices = array();
132
133    /**
134     * Jetpack_Plugin_Compatibility constructor.
135     */
136    protected function __construct() {
137        // Disable plugin activation for unsupported plugins.
138        add_action( 'load-plugins.php', array( $this, 'check_plugin_compatibility' ) );
139        // Replace "Activate" plugin link for plugins that should not be activated (plugins.php).
140        add_filter( 'plugin_action_links', array( $this, 'disable_plugin_activate_link' ), 10, 2 );
141        add_filter( 'network_admin_plugin_action_links', array( $this, 'disable_plugin_activate_link' ), 10, 2 );
142        // Replace "Install" plugin link for plugins that not should not be activated (plugin-install.php).
143        add_filter( 'plugin_install_action_links', array( $this, 'disable_plugin_install_link' ), 10, 2 );
144        // Print any notices about plugin deactivation.
145        add_action( 'admin_notices', array( $this, 'incompatible_plugin_notices' ) );
146    }
147
148    /**
149     * Public getter to return a singleton instance of Jetpack_Plugin_Compatibility.
150     */
151    public static function get_instance(): Jetpack_Plugin_Compatibility {
152        static $instance = null;
153
154        if ( null === $instance ) {
155            $instance = new static();
156        }
157
158        return $instance;
159    }
160
161    /**
162     * Deactivates incompatible plugins.
163     */
164    public function check_plugin_compatibility() {
165        foreach ( $this->incompatible_plugins as $plugin => $message ) {
166            if ( ! is_plugin_active( $plugin ) ) {
167                continue;
168            }
169
170            deactivate_plugins( $plugin );
171
172            $this->admin_notices[] = '<div class="notice notice-error is-dismissible"><p><strong>' . esc_html( $message ) . '</strong></p></div>';
173            unset( $_GET['activate'] );
174        }
175    }
176
177    /**
178     * Displays admin notices.
179     */
180    public function incompatible_plugin_notices() {
181        foreach ( $this->admin_notices as $notice ) {
182            echo wp_kses_post( $notice );
183        }
184    }
185
186    /**
187     * Disables plugin activations links for incompatible plugins.
188     *
189     * @param array  $actions     Plugin actions.
190     * @param string $plugin_file Plugin file.
191     *
192     * @return array Filtered array of plugin actions.
193     */
194    public function disable_plugin_activate_link( $actions, $plugin_file ) {
195        if ( ! empty( $this->incompatible_plugins[ $plugin_file ] ) ) {
196            $actions['activate'] = 'Disabled';
197            unset( $actions['edit'] );
198        }
199        return $actions;
200    }
201
202    /**
203     * Disables plugin install links for incompatible plugins.
204     *
205     * @param array $action_links Plugin actions.
206     * @param array $plugin       Plugin information.
207     *
208     * @return string[]
209     */
210    public function disable_plugin_install_link( $action_links, $plugin ) {
211        $needle = "{$plugin['slug']}/";
212        foreach ( $this->incompatible_plugins as $disallowed_plugin => $message ) {
213            /*
214            * The naming convention of $disallowed_plugin is <slug>/<file>.php so we are checking if
215            * the string $needle is included into $disallowed_plugin from the `0` position.
216            */
217            if ( strpos( $disallowed_plugin, $needle ) === 0 ) {
218                $action_links = array( 'Not Supported' );
219                break;
220            }
221        }
222
223        return $action_links;
224    }
225
226    /**
227     * Find the incompatible plugins on the site.
228     *
229     * @return array
230     */
231    public function find_incompatible_plugins(): array {
232        // We don't apply the standard Core 'all_plugins' filter, so we are truly looking at all standard plugins.
233        $standard_plugins = get_plugins();
234
235        $disallowed_plugins = $this->get_disallowed_plugins();
236
237        $incompatible_plugins_on_site = array();
238
239        foreach ( $standard_plugins as $plugin_file => $plugin_details ) {
240            if ( ! array_key_exists( $plugin_file, $disallowed_plugins ) ) {
241                continue;
242            }
243
244            $incompatible_plugins_on_site[ $plugin_file ] = array(
245                'message' => $disallowed_plugins[ $plugin_file ],
246                'details' => $plugin_details,
247                'status'  => $this->get_plugin_status( $plugin_file ),
248            );
249        }
250
251        $mu_plugins = get_mu_plugins();
252
253        foreach ( $mu_plugins as $mu_plugin_file => $mu_plugin_details ) {
254            if ( ! array_key_exists( $mu_plugin_file, $disallowed_plugins ) ) {
255                continue;
256            }
257
258            $incompatible_plugins_on_site[ $mu_plugin_file ] = array(
259                'message' => $disallowed_plugins[ $mu_plugin_file ],
260                'details' => $mu_plugin_details,
261                'status'  => 'must-use',
262            );
263        }
264
265        return $incompatible_plugins_on_site;
266    }
267
268    /**
269     * Helper function to return disallowed plugins.
270     * When possible, this function will include platform-level plugins.
271     *
272     * @return string[]
273     */
274    protected function get_disallowed_plugins(): array {
275        if ( ! class_exists( 'Atomic_Platform_Mu_Plugin' ) || ! method_exists( 'Atomic_Platform_Mu_Plugin', 'get_disallowed_plugins' ) ) {
276            return $this->incompatible_plugins;
277        }
278
279        $platform_mu_plugin = new Atomic_Platform_Mu_Plugin();
280
281        // We prefer product-level messages to platform messages when there are conflicts.
282        return array_merge( $platform_mu_plugin->get_disallowed_plugins(), $this->incompatible_plugins );
283    }
284
285    /**
286     * Helper function to determine the status of a standard plugin.
287     *
288     * @param  string $plugin_file The full plugin filename.
289     * @return 'active-network'|'active'|'inactive'
290     */
291    protected function get_plugin_status( string $plugin_file ): string {
292        if ( is_plugin_active_for_network( $plugin_file ) ) {
293            return 'active-network';
294        }
295
296        if ( is_plugin_active( $plugin_file ) ) {
297            return 'active';
298        }
299
300        return 'inactive';
301    }
302}